aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE.md37
-rw-r--r--.gitignore12
-rw-r--r--.travis.yml32
-rw-r--r--.tx/config2
-rw-r--r--CONTRIBUTING.md221
-rw-r--r--COPYING2
-rw-r--r--INSTALL5
-rw-r--r--INSTALL.md5
-rw-r--r--Makefile.am119
-rw-r--r--README.md9
-rwxr-xr-xautogen.sh4
-rw-r--r--build-aux/m4/ax_boost_base.m44
-rw-r--r--build-aux/m4/ax_cxx_compile_stdcxx.m48
-rw-r--r--build-aux/m4/bitcoin_find_bdb48.m4124
-rw-r--r--build-aux/m4/bitcoin_qt.m410
-rw-r--r--build-aux/m4/bitcoin_subdir_to_include.m44
-rw-r--r--build-aux/m4/l_atomic.m446
-rw-r--r--configure.ac253
-rw-r--r--contrib/README.md13
-rw-r--r--contrib/debian/bitcoin-qt.desktop5
-rw-r--r--contrib/debian/bitcoin-qt.manpages1
-rw-r--r--contrib/debian/bitcoin-tx.manpages1
-rw-r--r--contrib/debian/bitcoind.manpages5
-rw-r--r--contrib/debian/changelog125
-rw-r--r--contrib/debian/control55
-rw-r--r--contrib/debian/copyright13
-rw-r--r--contrib/debian/examples/bitcoin.conf37
-rw-r--r--contrib/debian/manpages/bitcoin-cli.121
-rw-r--r--contrib/debian/manpages/bitcoin-qt.113
-rw-r--r--contrib/debian/manpages/bitcoin.conf.519
-rw-r--r--contrib/debian/manpages/bitcoind.130
-rwxr-xr-xcontrib/debian/rules7
-rw-r--r--contrib/devtools/README.md78
-rwxr-xr-xcontrib/devtools/check-doc.py4
-rwxr-xr-xcontrib/devtools/clang-format-diff.py4
-rwxr-xr-xcontrib/devtools/clang-format.py62
-rwxr-xr-xcontrib/devtools/commit-script-check.sh39
-rwxr-xr-xcontrib/devtools/copyright_header.py610
-rwxr-xr-xcontrib/devtools/fix-copyright-headers.py46
-rwxr-xr-xcontrib/devtools/gen-manpages.sh29
-rwxr-xr-xcontrib/devtools/git-subtree-check.sh3
-rwxr-xr-xcontrib/devtools/github-merge.py145
-rwxr-xr-xcontrib/devtools/optimize-pngs.py5
-rwxr-xr-xcontrib/devtools/security-check.py53
-rwxr-xr-xcontrib/devtools/symbol-check.py2
-rwxr-xr-xcontrib/devtools/test-security-check.py6
-rwxr-xr-xcontrib/devtools/update-translations.py10
-rwxr-xr-xcontrib/gitian-build.sh392
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml2
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml2
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml13
-rw-r--r--contrib/gitian-keys/README.md16
-rw-r--r--contrib/gitian-keys/btcdrak-key.pgpbin8954 -> 4916 bytes
-rw-r--r--contrib/gitian-keys/jtimon-key.pgpbin0 -> 10892 bytes
-rw-r--r--contrib/init/README.md4
-rw-r--r--contrib/linearize/README.md52
-rw-r--r--contrib/linearize/example-linearize.cfg20
-rwxr-xr-xcontrib/linearize/linearize-data.py79
-rwxr-xr-xcontrib/linearize/linearize-hashes.py68
-rwxr-xr-xcontrib/macdeploy/custom_dsstore.py2
-rwxr-xr-xcontrib/macdeploy/detached-sig-apply.sh4
-rwxr-xr-xcontrib/macdeploy/detached-sig-create.sh6
-rwxr-xr-xcontrib/macdeploy/extract-osx-sdk.sh33
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus16
-rw-r--r--contrib/qos/README.md4
-rw-r--r--contrib/qos/tc.sh32
-rwxr-xr-xcontrib/qt_translations.py22
-rw-r--r--contrib/rpm/README.md2
-rw-r--r--contrib/rpm/bitcoin.spec16
-rw-r--r--contrib/seeds/README.md14
-rwxr-xr-xcontrib/seeds/generate-seeds.py6
-rwxr-xr-xcontrib/seeds/makeseeds.py17
-rw-r--r--contrib/seeds/nodes_main.txt1831
-rw-r--r--contrib/spendfrom/README.md35
-rw-r--r--contrib/spendfrom/setup.py9
-rwxr-xr-xcontrib/spendfrom/spendfrom.py267
-rw-r--r--contrib/testgen/base58.py4
-rwxr-xr-xcontrib/testgen/gen_base58_test_vectors.py6
-rwxr-xr-xcontrib/tidy_datadir.sh3
-rw-r--r--contrib/verify-commits/allow-revsig-commits104
-rwxr-xr-xcontrib/verify-commits/gpg.sh44
-rwxr-xr-xcontrib/verify-commits/pre-push-hook.sh4
-rw-r--r--contrib/verify-commits/trusted-keys4
-rw-r--r--contrib/verify-commits/trusted-sha512-root-commit1
-rwxr-xr-xcontrib/verify-commits/verify-commits.sh150
-rw-r--r--contrib/verifybinaries/README.md22
-rwxr-xr-xcontrib/verifybinaries/verify.sh22
-rwxr-xr-xcontrib/windeploy/detached-sig-create.sh34
-rw-r--r--contrib/windeploy/win-codesign.cert99
-rwxr-xr-xcontrib/zmq/zmq_sub.py103
-rwxr-xr-xcontrib/zmq/zmq_sub3.4.py89
-rwxr-xr-xdepends/config.guess22
-rw-r--r--depends/config.site.in4
-rwxr-xr-xdepends/config.sub43
-rw-r--r--depends/hosts/darwin.mk2
-rw-r--r--depends/packages/boost.mk6
-rw-r--r--depends/packages/dbus.mk6
-rw-r--r--depends/packages/expat.mk4
-rw-r--r--depends/packages/fontconfig.mk4
-rw-r--r--depends/packages/freetype.mk4
-rw-r--r--depends/packages/libevent.mk11
-rw-r--r--depends/packages/native_biplist.mk5
-rw-r--r--depends/packages/native_ccache.mk6
-rw-r--r--depends/packages/native_cctools.mk3
-rw-r--r--depends/packages/native_comparisontool.mk21
-rw-r--r--depends/packages/native_ds_store.mk6
-rw-r--r--depends/packages/packages.mk9
-rw-r--r--depends/packages/qrencode.mk2
-rw-r--r--depends/packages/qt.mk37
-rw-r--r--depends/packages/qt46.mk66
-rw-r--r--depends/packages/zeromq.mk15
-rw-r--r--depends/packages/zlib.mk27
-rw-r--r--depends/patches/libevent/reuseaddr.patch21
-rw-r--r--depends/patches/native_biplist/sorted_list.patch29
-rw-r--r--depends/patches/qt/fix-xcb-include-order.patch18
-rw-r--r--depends/patches/qt/fix_qt_pkgconfig.patch6
-rw-r--r--depends/patches/qt/mac-qmake.conf15
-rw-r--r--depends/patches/qt/mingw-uuidof.patch18
-rw-r--r--depends/patches/qt/pidlist_absolute.patch12
-rw-r--r--depends/patches/qt46/stlfix.patch10
-rw-r--r--depends/patches/zeromq/9114d3957725acd34aa8b8d011585812f3369411.patch22
-rw-r--r--depends/patches/zeromq/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch22
-rw-r--r--doc/.gitignore1
-rw-r--r--doc/Doxyfile1752
-rw-r--r--doc/Doxyfile.in2460
-rw-r--r--doc/README.md16
-rw-r--r--doc/README_osx.md19
-rw-r--r--doc/README_windows.txt4
-rw-r--r--doc/REST-interface.md2
-rw-r--r--doc/bips.md6
-rw-r--r--doc/build-openbsd.md50
-rw-r--r--doc/build-osx.md10
-rw-r--r--doc/build-unix.md52
-rw-r--r--doc/build-windows.md86
-rw-r--r--doc/developer-notes.md167
-rw-r--r--doc/files.md1
-rw-r--r--doc/fuzzing.md66
-rw-r--r--doc/gitian-building.md14
-rw-r--r--doc/gitian-building/create_vm_memsize.pngbin89475 -> 22158 bytes
-rw-r--r--doc/man/Makefile.am13
-rw-r--r--doc/man/bitcoin-cli.186
-rw-r--r--doc/man/bitcoin-qt.1546
-rw-r--r--doc/man/bitcoin-tx.1122
-rw-r--r--doc/man/bitcoind.1525
-rw-r--r--doc/multiwallet-qt.md48
-rw-r--r--doc/reduce-traffic.md3
-rw-r--r--doc/release-notes.md244
-rw-r--r--doc/release-notes/release-notes-0.12.1.md198
-rw-r--r--doc/release-notes/release-notes-0.13.0.md868
-rw-r--r--doc/release-notes/release-notes-0.13.1.md410
-rw-r--r--doc/release-notes/release-notes-0.13.2.md178
-rw-r--r--doc/release-notes/release-notes-0.14.0.md873
-rw-r--r--doc/release-notes/release-notes-0.14.1.md143
-rw-r--r--doc/release-process.md81
-rw-r--r--doc/shared-libraries.md5
-rw-r--r--doc/tor.md19
-rw-r--r--doc/translation_process.md8
-rw-r--r--doc/travis-ci.md (renamed from doc/travis-ci.txt)9
-rw-r--r--doc/unit-tests.md18
-rw-r--r--doc/zmq.md4
-rw-r--r--qa/README.md87
-rwxr-xr-xqa/pull-tester/rpc-tests.py341
-rw-r--r--qa/pull-tester/run-bitcoind-for-test.sh.in36
-rw-r--r--qa/pull-tester/tests_config.py.in14
-rwxr-xr-xqa/rpc-tests/disablewallet.py48
-rwxr-xr-xqa/rpc-tests/keypool.py75
-rwxr-xr-xqa/rpc-tests/maxblocksinflight.py96
-rwxr-xr-xqa/rpc-tests/nodehandling.py86
-rwxr-xr-xqa/rpc-tests/p2p-mempool.py99
-rwxr-xr-xqa/rpc-tests/rpcbind_test.py147
-rwxr-xr-xqa/rpc-tests/segwit.py209
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py214
-rw-r--r--share/certs/PrivateKeyNotes.md2
-rwxr-xr-xshare/genbuild.sh4
-rw-r--r--share/qt/Info.plist.in2
-rwxr-xr-xshare/qt/extract_strings_qt.py6
-rw-r--r--share/qt/protobuf.pri35
-rwxr-xr-xshare/rpcuser/rpcuser.py2
-rw-r--r--src/.clang-format2
-rw-r--r--src/Makefile.am52
-rw-r--r--src/Makefile.bench.include36
-rw-r--r--src/Makefile.leveldb.include5
-rw-r--r--src/Makefile.qt.include45
-rw-r--r--src/Makefile.qttest.include35
-rw-r--r--src/Makefile.test.include83
-rw-r--r--src/addrdb.cpp218
-rw-r--r--src/addrdb.h102
-rw-r--r--src/addrman.cpp26
-rw-r--r--src/addrman.h90
-rw-r--r--src/amount.h47
-rw-r--r--src/arith_uint256.cpp8
-rw-r--r--src/arith_uint256.h2
-rw-r--r--src/base58.cpp14
-rw-r--r--src/base58.h2
-rw-r--r--src/bench/Examples.cpp4
-rw-r--r--src/bench/base58.cpp4
-rw-r--r--src/bench/bench.cpp57
-rw-r--r--src/bench/bench.h17
-rw-r--r--src/bench/bench_bitcoin.cpp4
-rw-r--r--src/bench/ccoins_caching.cpp87
-rw-r--r--src/bench/checkblock.cpp56
-rw-r--r--src/bench/checkqueue.cpp103
-rw-r--r--src/bench/coin_selection.cpp60
-rw-r--r--src/bench/crypto_hash.cpp35
-rw-r--r--src/bench/data/block413567.rawbin0 -> 999887 bytes
-rw-r--r--src/bench/lockedpool.cpp47
-rw-r--r--src/bench/mempool_eviction.cpp114
-rw-r--r--src/bench/perf.cpp53
-rw-r--r--src/bench/perf.h37
-rw-r--r--src/bench/prevector_destructor.cpp36
-rw-r--r--src/bench/verify_script.cpp102
-rw-r--r--src/bitcoin-cli.cpp166
-rw-r--r--src/bitcoin-tx.cpp425
-rw-r--r--src/bitcoind.cpp74
-rw-r--r--src/blockencodings.cpp72
-rw-r--r--src/blockencodings.h41
-rw-r--r--src/bloom.cpp40
-rw-r--r--src/bloom.h4
-rw-r--r--src/chain.cpp11
-rw-r--r--src/chain.h51
-rw-r--r--src/chainparams.cpp126
-rw-r--r--src/chainparams.h38
-rw-r--r--src/chainparamsbase.cpp24
-rw-r--r--src/chainparamsbase.h16
-rw-r--r--src/chainparamsseeds.h1831
-rw-r--r--src/checkpoints.cpp54
-rw-r--r--src/checkpoints.h7
-rw-r--r--src/checkqueue.h24
-rw-r--r--src/clientversion.cpp2
-rw-r--r--src/clientversion.h28
-rw-r--r--src/coins.cpp65
-rw-r--r--src/coins.h68
-rw-r--r--src/compat.h14
-rw-r--r--src/compat/byteswap.h21
-rw-r--r--src/compat/endian.h2
-rw-r--r--src/compressor.h16
-rw-r--r--src/consensus/consensus.h6
-rw-r--r--src/consensus/merkle.cpp8
-rw-r--r--src/consensus/params.h16
-rw-r--r--src/consensus/validation.h8
-rw-r--r--src/core_io.h25
-rw-r--r--src/core_memusage.h36
-rw-r--r--src/core_read.cpp36
-rw-r--r--src/core_write.cpp59
-rw-r--r--src/crypto/aes.h2
-rw-r--r--src/crypto/chacha20.cpp180
-rw-r--r--src/crypto/chacha20.h26
-rw-r--r--src/crypto/common.h57
-rw-r--r--src/crypto/ctaes/ctaes.c8
-rw-r--r--src/crypto/ctaes/test.c2
-rw-r--r--src/crypto/ripemd160.h2
-rw-r--r--src/crypto/sha1.h2
-rw-r--r--src/crypto/sha256.h2
-rw-r--r--src/crypto/sha512.h2
-rw-r--r--src/cuckoocache.h450
-rw-r--r--src/dbwrapper.cpp71
-rw-r--r--src/dbwrapper.h59
-rw-r--r--src/fs.cpp17
-rw-r--r--src/fs.h24
-rw-r--r--src/hash.cpp4
-rw-r--r--src/hash.h22
-rw-r--r--src/httprpc.cpp42
-rw-r--r--src/httpserver.cpp172
-rw-r--r--src/httpserver.h16
-rw-r--r--src/indirectmap.h4
-rw-r--r--src/init.cpp790
-rw-r--r--src/init.h27
-rw-r--r--src/key.cpp50
-rw-r--r--src/key.h57
-rw-r--r--src/keystore.cpp2
-rw-r--r--src/leveldb/.travis.yml13
-rw-r--r--src/leveldb/Makefile467
-rw-r--r--src/leveldb/README51
-rw-r--r--src/leveldb/README.md39
-rwxr-xr-xsrc/leveldb/build_detect_platform2
-rw-r--r--src/leveldb/db/corruption_test.cc2
-rw-r--r--src/leveldb/db/db_bench.cc24
-rw-r--r--src/leveldb/db/db_impl.cc194
-rw-r--r--src/leveldb/db/db_impl.h8
-rw-r--r--src/leveldb/db/db_test.cc32
-rw-r--r--src/leveldb/db/fault_injection_test.cc554
-rw-r--r--src/leveldb/db/leveldbutil.cc (renamed from src/leveldb/db/leveldb_main.cc)0
-rw-r--r--src/leveldb/db/log_reader.cc22
-rw-r--r--src/leveldb/db/log_reader.h5
-rw-r--r--src/leveldb/db/log_test.cc101
-rw-r--r--src/leveldb/db/log_writer.cc17
-rw-r--r--src/leveldb/db/log_writer.h6
-rw-r--r--src/leveldb/db/memtable.h5
-rw-r--r--src/leveldb/db/recovery_test.cc324
-rw-r--r--src/leveldb/db/skiplist.h8
-rw-r--r--src/leveldb/db/skiplist_test.cc2
-rw-r--r--src/leveldb/db/snapshot.h1
-rw-r--r--src/leveldb/db/version_set.cc40
-rw-r--r--src/leveldb/db/version_set.h4
-rw-r--r--src/leveldb/db/write_batch_internal.h1
-rw-r--r--src/leveldb/doc/index.html2
-rw-r--r--src/leveldb/helpers/memenv/memenv.cc13
-rw-r--r--src/leveldb/helpers/memenv/memenv_test.cc13
-rw-r--r--src/leveldb/include/leveldb/cache.h11
-rw-r--r--src/leveldb/include/leveldb/db.h4
-rw-r--r--src/leveldb/include/leveldb/env.h18
-rw-r--r--src/leveldb/include/leveldb/iterator.h2
-rw-r--r--src/leveldb/include/leveldb/options.h6
-rw-r--r--src/leveldb/include/leveldb/status.h6
-rw-r--r--src/leveldb/port/atomic_pointer.h19
-rw-r--r--src/leveldb/port/port_posix.cc1
-rw-r--r--src/leveldb/table/filter_block.cc4
-rw-r--r--src/leveldb/table/format.cc3
-rw-r--r--src/leveldb/table/iterator_wrapper.h3
-rw-r--r--src/leveldb/table/table.cc2
-rw-r--r--src/leveldb/table/table_test.cc20
-rw-r--r--src/leveldb/util/arena.cc6
-rw-r--r--src/leveldb/util/arena.h10
-rw-r--r--src/leveldb/util/bloom.cc2
-rw-r--r--src/leveldb/util/bloom_test.cc3
-rw-r--r--src/leveldb/util/cache.cc136
-rw-r--r--src/leveldb/util/cache_test.cc42
-rw-r--r--src/leveldb/util/env.cc4
-rw-r--r--src/leveldb/util/env_posix.cc13
-rw-r--r--src/leveldb/util/env_win.cc37
-rw-r--r--src/leveldb/util/options.cc2
-rw-r--r--src/leveldb/util/testutil.h10
-rw-r--r--src/limitedmap.h9
-rw-r--r--src/memusage.h22
-rw-r--r--src/merkleblock.cpp22
-rw-r--r--src/merkleblock.h8
-rw-r--r--src/miner.cpp327
-rw-r--r--src/miner.h43
-rw-r--r--src/net.cpp1622
-rw-r--r--src/net.h876
-rw-r--r--src/net_processing.cpp3298
-rw-r--r--src/net_processing.h63
-rw-r--r--src/netaddress.cpp710
-rw-r--r--src/netaddress.h170
-rw-r--r--src/netbase.cpp927
-rw-r--r--src/netbase.h172
-rw-r--r--src/netmessagemaker.h36
-rw-r--r--src/noui.cpp2
-rw-r--r--src/policy/feerate.cpp (renamed from src/amount.cpp)4
-rw-r--r--src/policy/feerate.h54
-rw-r--r--src/policy/fees.cpp480
-rw-r--r--src/policy/fees.h241
-rw-r--r--src/policy/policy.cpp123
-rw-r--r--src/policy/policy.h61
-rw-r--r--src/policy/rbf.cpp2
-rw-r--r--src/policy/rbf.h2
-rw-r--r--src/pow.cpp7
-rw-r--r--src/pow.h2
-rw-r--r--src/prevector.h42
-rw-r--r--src/primitives/block.cpp10
-rw-r--r--src/primitives/block.h17
-rw-r--r--src/primitives/transaction.cpp68
-rw-r--r--src/primitives/transaction.h306
-rw-r--r--src/protocol.cpp12
-rw-r--r--src/protocol.h71
-rw-r--r--src/pubkey.cpp8
-rw-r--r--src/pubkey.h34
-rw-r--r--src/qt/addressbookpage.cpp20
-rw-r--r--src/qt/addresstablemodel.cpp14
-rw-r--r--src/qt/askpassphrasedialog.cpp10
-rw-r--r--src/qt/bantablemodel.cpp18
-rw-r--r--src/qt/bantablemodel.h5
-rw-r--r--src/qt/bitcoin.cpp114
-rw-r--r--src/qt/bitcoin.qrc3
-rw-r--r--src/qt/bitcoin_locale.qrc5
-rw-r--r--src/qt/bitcoingui.cpp232
-rw-r--r--src/qt/bitcoingui.h27
-rw-r--r--src/qt/bitcoinstrings.cpp84
-rw-r--r--src/qt/bitcoinunits.cpp2
-rw-r--r--src/qt/bitcoinunits.h2
-rw-r--r--src/qt/callback.h30
-rw-r--r--src/qt/clientmodel.cpp100
-rw-r--r--src/qt/clientmodel.h19
-rw-r--r--src/qt/coincontroldialog.cpp198
-rw-r--r--src/qt/coincontroldialog.h48
-rw-r--r--src/qt/csvmodelwriter.cpp10
-rw-r--r--src/qt/editaddressdialog.cpp20
-rw-r--r--src/qt/forms/coincontroldialog.ui61
-rw-r--r--src/qt/forms/debugwindow.ui29
-rw-r--r--src/qt/forms/intro.ui35
-rw-r--r--src/qt/forms/modaloverlay.ui376
-rw-r--r--src/qt/forms/optionsdialog.ui102
-rw-r--r--src/qt/forms/overviewpage.ui9
-rw-r--r--src/qt/forms/sendcoinsdialog.ui99
-rw-r--r--src/qt/guiconstants.h2
-rw-r--r--src/qt/guiutil.cpp173
-rw-r--r--src/qt/guiutil.h52
-rw-r--r--src/qt/intro.cpp52
-rw-r--r--src/qt/intro.h7
-rw-r--r--src/qt/locale/bitcoin_af.ts693
-rw-r--r--src/qt/locale/bitcoin_af_ZA.ts429
-rw-r--r--src/qt/locale/bitcoin_ar.ts887
-rw-r--r--src/qt/locale/bitcoin_be_BY.ts663
-rw-r--r--src/qt/locale/bitcoin_bg.ts1059
-rw-r--r--src/qt/locale/bitcoin_bg_BG.ts195
-rw-r--r--src/qt/locale/bitcoin_ca.ts1347
-rw-r--r--src/qt/locale/bitcoin_ca@valencia.ts1197
-rw-r--r--src/qt/locale/bitcoin_ca_ES.ts1345
-rw-r--r--src/qt/locale/bitcoin_cs.ts1843
-rw-r--r--src/qt/locale/bitcoin_cs_CZ.ts300
-rw-r--r--src/qt/locale/bitcoin_cy.ts75
-rw-r--r--src/qt/locale/bitcoin_da.ts1597
-rw-r--r--src/qt/locale/bitcoin_de.ts1503
-rw-r--r--src/qt/locale/bitcoin_el.ts45
-rw-r--r--src/qt/locale/bitcoin_el_GR.ts127
-rw-r--r--src/qt/locale/bitcoin_en.ts2238
-rw-r--r--src/qt/locale/bitcoin_en_GB.ts315
-rw-r--r--src/qt/locale/bitcoin_eo.ts135
-rw-r--r--src/qt/locale/bitcoin_es.ts1498
-rw-r--r--src/qt/locale/bitcoin_es_AR.ts43
-rw-r--r--src/qt/locale/bitcoin_es_CL.ts84
-rw-r--r--src/qt/locale/bitcoin_es_CO.ts47
-rw-r--r--src/qt/locale/bitcoin_es_DO.ts111
-rw-r--r--src/qt/locale/bitcoin_es_ES.ts3470
-rw-r--r--src/qt/locale/bitcoin_es_MX.ts71
-rw-r--r--src/qt/locale/bitcoin_es_UY.ts65
-rw-r--r--src/qt/locale/bitcoin_es_VE.ts87
-rw-r--r--src/qt/locale/bitcoin_et.ts909
-rw-r--r--src/qt/locale/bitcoin_et_EE.ts747
-rw-r--r--src/qt/locale/bitcoin_eu_ES.ts481
-rw-r--r--src/qt/locale/bitcoin_fa.ts467
-rw-r--r--src/qt/locale/bitcoin_fa_IR.ts61
-rw-r--r--src/qt/locale/bitcoin_fi.ts389
-rw-r--r--src/qt/locale/bitcoin_fr.ts1771
-rw-r--r--src/qt/locale/bitcoin_fr_CA.ts45
-rw-r--r--src/qt/locale/bitcoin_fr_FR.ts127
-rw-r--r--src/qt/locale/bitcoin_gl.ts109
-rw-r--r--src/qt/locale/bitcoin_he.ts239
-rw-r--r--src/qt/locale/bitcoin_hi_IN.ts53
-rw-r--r--src/qt/locale/bitcoin_hr.ts133
-rw-r--r--src/qt/locale/bitcoin_hu.ts171
-rw-r--r--src/qt/locale/bitcoin_id_ID.ts143
-rw-r--r--src/qt/locale/bitcoin_it.ts595
-rw-r--r--src/qt/locale/bitcoin_it_IT.ts49
-rw-r--r--src/qt/locale/bitcoin_ja.ts1531
-rw-r--r--src/qt/locale/bitcoin_ka.ts119
-rw-r--r--src/qt/locale/bitcoin_kk_KZ.ts83
-rw-r--r--src/qt/locale/bitcoin_ko_KR.ts885
-rw-r--r--src/qt/locale/bitcoin_ku_IQ.ts149
-rw-r--r--src/qt/locale/bitcoin_ky.ts105
-rw-r--r--src/qt/locale/bitcoin_la.ts81
-rw-r--r--src/qt/locale/bitcoin_lt.ts77
-rw-r--r--src/qt/locale/bitcoin_lv_LV.ts103
-rw-r--r--src/qt/locale/bitcoin_mk_MK.ts87
-rw-r--r--src/qt/locale/bitcoin_mn.ts57
-rw-r--r--src/qt/locale/bitcoin_ms_MY.ts48
-rw-r--r--src/qt/locale/bitcoin_nb.ts243
-rw-r--r--src/qt/locale/bitcoin_ne.ts555
-rw-r--r--src/qt/locale/bitcoin_nl.ts1285
-rw-r--r--src/qt/locale/bitcoin_pam.ts69
-rw-r--r--src/qt/locale/bitcoin_pl.ts913
-rw-r--r--src/qt/locale/bitcoin_pt_BR.ts1645
-rw-r--r--src/qt/locale/bitcoin_pt_PT.ts711
-rw-r--r--src/qt/locale/bitcoin_ro.ts641
-rw-r--r--src/qt/locale/bitcoin_ro_RO.ts179
-rw-r--r--src/qt/locale/bitcoin_ru.ts1559
-rw-r--r--src/qt/locale/bitcoin_ru_RU.ts61
-rw-r--r--src/qt/locale/bitcoin_sk.ts393
-rw-r--r--src/qt/locale/bitcoin_sl_SI.ts201
-rw-r--r--src/qt/locale/bitcoin_sq.ts395
-rw-r--r--src/qt/locale/bitcoin_sr.ts117
-rw-r--r--src/qt/locale/bitcoin_sr@latin.ts257
-rw-r--r--src/qt/locale/bitcoin_sv.ts616
-rw-r--r--src/qt/locale/bitcoin_ta.ts109
-rw-r--r--src/qt/locale/bitcoin_th_TH.ts111
-rw-r--r--src/qt/locale/bitcoin_tr.ts1849
-rw-r--r--src/qt/locale/bitcoin_tr_TR.ts43
-rw-r--r--src/qt/locale/bitcoin_uk.ts195
-rw-r--r--src/qt/locale/bitcoin_ur_PK.ts45
-rw-r--r--src/qt/locale/bitcoin_uz@Cyrl.ts119
-rw-r--r--src/qt/locale/bitcoin_vi.ts43
-rw-r--r--src/qt/locale/bitcoin_vi_VN.ts623
-rw-r--r--src/qt/locale/bitcoin_zh.ts71
-rw-r--r--src/qt/locale/bitcoin_zh_CN.ts1559
-rw-r--r--src/qt/locale/bitcoin_zh_HK.ts43
-rw-r--r--src/qt/locale/bitcoin_zh_TW.ts1529
-rw-r--r--src/qt/modaloverlay.cpp172
-rw-r--r--src/qt/modaloverlay.h50
-rw-r--r--src/qt/networkstyle.cpp8
-rw-r--r--src/qt/notificator.cpp14
-rw-r--r--src/qt/optionsdialog.cpp36
-rw-r--r--src/qt/optionsdialog.h3
-rw-r--r--src/qt/optionsmodel.cpp42
-rw-r--r--src/qt/optionsmodel.h8
-rw-r--r--src/qt/overviewpage.cpp22
-rw-r--r--src/qt/overviewpage.h7
-rw-r--r--src/qt/paymentrequest.proto2
-rw-r--r--src/qt/paymentrequestplus.cpp22
-rw-r--r--src/qt/paymentrequestplus.h5
-rw-r--r--src/qt/paymentserver.cpp67
-rw-r--r--src/qt/paymentserver.h13
-rw-r--r--src/qt/peertablemodel.cpp37
-rw-r--r--src/qt/peertablemodel.h14
-rw-r--r--src/qt/platformstyle.cpp12
-rw-r--r--src/qt/qvalidatedlineedit.cpp10
-rw-r--r--src/qt/qvaluecombobox.cpp6
-rw-r--r--src/qt/receivecoinsdialog.cpp72
-rw-r--r--src/qt/receivecoinsdialog.h4
-rw-r--r--src/qt/receiverequestdialog.cpp16
-rw-r--r--src/qt/receiverequestdialog.h2
-rw-r--r--src/qt/recentrequeststablemodel.cpp4
-rw-r--r--src/qt/recentrequeststablemodel.h5
-rw-r--r--src/qt/res/icons/hd_disabled.pngbin0 -> 4328 bytes
-rw-r--r--src/qt/res/icons/hd_enabled.pngbin0 -> 1889 bytes
-rw-r--r--src/qt/res/icons/network_disabled.pngbin0 -> 2438 bytes
-rwxr-xr-xsrc/qt/res/movies/makespinner.sh4
-rw-r--r--src/qt/res/src/connect-0.svg4
-rw-r--r--src/qt/res/src/connect-1.svg4
-rw-r--r--src/qt/res/src/connect-2.svg4
-rw-r--r--src/qt/res/src/connect-3.svg4
-rw-r--r--src/qt/res/src/connect-4.svg4
-rw-r--r--src/qt/res/src/hd_disabled.svg26
-rw-r--r--src/qt/res/src/hd_enabled.svg13
-rw-r--r--src/qt/res/src/network_disabled.svg49
-rw-r--r--src/qt/rpcconsole.cpp541
-rw-r--r--src/qt/rpcconsole.h19
-rw-r--r--src/qt/sendcoinsdialog.cpp136
-rw-r--r--src/qt/sendcoinsdialog.h5
-rw-r--r--src/qt/sendcoinsentry.cpp14
-rw-r--r--src/qt/signverifymessagedialog.cpp14
-rw-r--r--src/qt/splashscreen.cpp15
-rw-r--r--src/qt/splashscreen.h7
-rw-r--r--src/qt/test/compattests.cpp23
-rw-r--r--src/qt/test/compattests.h19
-rw-r--r--src/qt/test/paymentservertests.cpp2
-rw-r--r--src/qt/test/rpcnestedtests.cpp159
-rw-r--r--src/qt/test/rpcnestedtests.h25
-rw-r--r--src/qt/test/test_main.cpp58
-rw-r--r--src/qt/test/wallettests.cpp119
-rw-r--r--src/qt/test/wallettests.h15
-rw-r--r--src/qt/transactiondesc.cpp35
-rw-r--r--src/qt/transactiondescdialog.cpp2
-rw-r--r--src/qt/transactionfilterproxy.cpp10
-rw-r--r--src/qt/transactionrecord.cpp37
-rw-r--r--src/qt/transactionrecord.h14
-rw-r--r--src/qt/transactiontablemodel.cpp22
-rw-r--r--src/qt/transactiontablemodel.h2
-rw-r--r--src/qt/transactionview.cpp24
-rw-r--r--src/qt/transactionview.h2
-rw-r--r--src/qt/utilitydialog.cpp12
-rw-r--r--src/qt/utilitydialog.h4
-rw-r--r--src/qt/walletframe.cpp16
-rw-r--r--src/qt/walletframe.h15
-rw-r--r--src/qt/walletmodel.cpp69
-rw-r--r--src/qt/walletmodel.h26
-rw-r--r--src/qt/walletmodeltransaction.cpp10
-rw-r--r--src/qt/walletview.cpp56
-rw-r--r--src/qt/walletview.h9
-rw-r--r--src/qt/winshutdownmonitor.cpp2
-rw-r--r--src/random.cpp213
-rw-r--r--src/random.h114
-rw-r--r--src/rest.cpp110
-rw-r--r--src/reverselock.h8
-rw-r--r--src/rpc/blockchain.cpp716
-rw-r--r--src/rpc/blockchain.h40
-rw-r--r--src/rpc/client.cpp227
-rw-r--r--src/rpc/client.h7
-rw-r--r--src/rpc/mining.cpp450
-rw-r--r--src/rpc/misc.cpp434
-rw-r--r--src/rpc/net.cpp338
-rw-r--r--src/rpc/protocol.cpp31
-rw-r--r--src/rpc/protocol.h70
-rw-r--r--src/rpc/rawtransaction.cpp396
-rw-r--r--src/rpc/register.h12
-rw-r--r--src/rpc/server.cpp224
-rw-r--r--src/rpc/server.h37
-rw-r--r--src/scheduler.cpp25
-rw-r--r--src/scheduler.h9
-rw-r--r--src/script/bitcoinconsensus.cpp26
-rw-r--r--src/script/bitcoinconsensus.h8
-rw-r--r--src/script/interpreter.cpp180
-rw-r--r--src/script/interpreter.h29
-rw-r--r--src/script/ismine.cpp74
-rw-r--r--src/script/ismine.h13
-rw-r--r--src/script/script.cpp12
-rw-r--r--src/script/script.h17
-rw-r--r--src/script/script_error.cpp8
-rw-r--r--src/script/script_error.h7
-rw-r--r--src/script/sigcache.cpp79
-rw-r--r--src/script/sigcache.h36
-rw-r--r--src/script/sign.cpp43
-rw-r--r--src/script/sign.h6
-rw-r--r--src/script/standard.cpp26
-rw-r--r--src/script/standard.h2
-rw-r--r--src/secp256k1/.gitignore20
-rw-r--r--src/secp256k1/.travis.yml18
-rw-r--r--src/secp256k1/Makefile.am90
-rw-r--r--src/secp256k1/README.md2
-rw-r--r--src/secp256k1/build-aux/m4/ax_jni_include_dir.m4140
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m48
-rw-r--r--src/secp256k1/configure.ac158
-rw-r--r--src/secp256k1/include/secp256k1.h14
-rw-r--r--src/secp256k1/include/secp256k1_schnorr.h173
-rw-r--r--src/secp256k1/libsecp256k1.pc.in2
-rw-r--r--src/secp256k1/sage/group_prover.sage322
-rw-r--r--src/secp256k1/sage/secp256k1.sage306
-rw-r--r--src/secp256k1/sage/weierstrass_prover.sage264
-rw-r--r--src/secp256k1/src/asm/field_10x26_arm.s919
-rw-r--r--src/secp256k1/src/bench_ecdh.c3
-rw-r--r--src/secp256k1/src/bench_internal.c34
-rw-r--r--src/secp256k1/src/bench_verify.c44
-rw-r--r--src/secp256k1/src/ecdsa_impl.h18
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h69
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h2
-rw-r--r--src/secp256k1/src/ecmult_impl.h21
-rw-r--r--src/secp256k1/src/field.h15
-rw-r--r--src/secp256k1/src/field_10x26_impl.h12
-rw-r--r--src/secp256k1/src/field_5x52_impl.h1
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h4
-rw-r--r--src/secp256k1/src/field_impl.h38
-rw-r--r--src/secp256k1/src/group.h9
-rw-r--r--src/secp256k1/src/group_impl.h112
-rw-r--r--src/secp256k1/src/hash.h2
-rw-r--r--src/secp256k1/src/hash_impl.h10
-rw-r--r--src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java440
-rw-r--r--src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java226
-rw-r--r--src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java45
-rw-r--r--src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java51
-rw-r--r--src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c378
-rw-r--r--src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h104
-rw-r--r--src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c15
-rw-r--r--src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h22
-rw-r--r--src/secp256k1/src/modules/ecdh/Makefile.am.include2
-rw-r--r--src/secp256k1/src/modules/recovery/Makefile.am.include2
-rwxr-xr-x[-rw-r--r--]src/secp256k1/src/modules/recovery/main_impl.h4
-rw-r--r--src/secp256k1/src/modules/schnorr/Makefile.am.include10
-rw-r--r--src/secp256k1/src/modules/schnorr/main_impl.h164
-rw-r--r--src/secp256k1/src/modules/schnorr/schnorr.h20
-rw-r--r--src/secp256k1/src/modules/schnorr/schnorr_impl.h207
-rw-r--r--src/secp256k1/src/modules/schnorr/tests_impl.h175
-rw-r--r--src/secp256k1/src/num.h6
-rw-r--r--src/secp256k1/src/num_gmp_impl.h26
-rw-r--r--src/secp256k1/src/scalar.h4
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h26
-rw-r--r--src/secp256k1/src/scalar_impl.h41
-rw-r--r--src/secp256k1/src/scalar_low.h15
-rw-r--r--src/secp256k1/src/scalar_low_impl.h114
-rwxr-xr-x[-rw-r--r--]src/secp256k1/src/secp256k1.c19
-rw-r--r--src/secp256k1/src/tests.c202
-rw-r--r--src/secp256k1/src/tests_exhaustive.c329
-rw-r--r--src/serialize.h576
-rw-r--r--src/streams.h211
-rw-r--r--src/support/allocators/secure.h14
-rw-r--r--src/support/cleanse.h1
-rw-r--r--src/support/events.h56
-rw-r--r--src/support/lockedpool.cpp385
-rw-r--r--src/support/lockedpool.h231
-rw-r--r--src/support/pagelocker.cpp70
-rw-r--r--src/support/pagelocker.h177
-rw-r--r--src/sync.cpp54
-rw-r--r--src/sync.h9
-rw-r--r--src/test/Checkpoints_tests.cpp27
-rw-r--r--src/test/DoS_tests.cpp108
-rw-r--r--src/test/README.md59
-rw-r--r--src/test/addrman_tests.cpp376
-rw-r--r--src/test/allocator_tests.cpp292
-rw-r--r--src/test/amount_tests.cpp39
-rw-r--r--src/test/arith_uint256_tests.cpp4
-rw-r--r--src/test/base58_tests.cpp7
-rw-r--r--src/test/bctest.py54
-rw-r--r--src/test/bip32_tests.cpp13
-rwxr-xr-xsrc/test/bitcoin-util-test.py13
-rw-r--r--src/test/blockencodings_tests.cpp129
-rw-r--r--src/test/bloom_tests.cpp90
-rw-r--r--src/test/bswap_tests.cpp26
-rw-r--r--src/test/buildenv.py.in2
-rw-r--r--src/test/checkqueue_tests.cpp442
-rw-r--r--src/test/coins_tests.cpp552
-rw-r--r--src/test/crypto_tests.cpp90
-rw-r--r--src/test/cuckoocache_tests.cpp382
-rw-r--r--src/test/data/bitcoin-util-test.json103
-rw-r--r--src/test/data/script_tests.json484
-rw-r--r--src/test/data/tx_invalid.json28
-rw-r--r--src/test/data/tx_valid.json45
-rw-r--r--src/test/data/txcreate2.hex1
-rw-r--r--src/test/dbwrapper_tests.cpp54
-rw-r--r--src/test/hash_tests.cpp12
-rw-r--r--src/test/key_tests.cpp48
-rw-r--r--src/test/limitedmap_tests.cpp6
-rw-r--r--src/test/main_tests.cpp12
-rw-r--r--src/test/mempool_tests.cpp127
-rw-r--r--src/test/merkle_tests.cpp14
-rw-r--r--src/test/miner_tests.cpp128
-rw-r--r--src/test/multisig_tests.cpp24
-rw-r--r--src/test/net_tests.cpp79
-rw-r--r--src/test/netbase_tests.cpp291
-rw-r--r--src/test/pmt_tests.cpp11
-rw-r--r--src/test/policyestimator_tests.cpp150
-rw-r--r--src/test/pow_tests.cpp34
-rw-r--r--src/test/prevector_tests.cpp85
-rw-r--r--src/test/raii_event_tests.cpp94
-rw-r--r--src/test/random_tests.cpp53
-rw-r--r--src/test/reverselock_tests.cpp2
-rw-r--r--src/test/rpc_tests.cpp183
-rw-r--r--src/test/scheduler_tests.cpp10
-rw-r--r--src/test/script_P2SH_tests.cpp26
-rw-r--r--src/test/script_tests.cpp207
-rw-r--r--src/test/scriptnum_tests.cpp6
-rw-r--r--src/test/serialize_tests.cpp82
-rw-r--r--src/test/sighash_tests.cpp12
-rw-r--r--src/test/sigopcount_tests.cpp58
-rw-r--r--src/test/skiplist_tests.cpp47
-rw-r--r--src/test/streams_tests.cpp63
-rw-r--r--src/test/test_bitcoin.cpp77
-rw-r--r--src/test/test_bitcoin.h21
-rw-r--r--src/test/test_bitcoin_fuzzy.cpp258
-rw-r--r--src/test/test_bitcoin_main.cpp26
-rw-r--r--src/test/test_random.h29
-rw-r--r--src/test/testutil.cpp24
-rw-r--r--src/test/testutil.h4
-rw-r--r--src/test/timedata_tests.cpp2
-rw-r--r--src/test/transaction_tests.cpp262
-rw-r--r--src/test/txvalidationcache_tests.cpp7
-rw-r--r--src/test/uint256_tests.cpp48
-rw-r--r--src/test/univalue_tests.cpp41
-rw-r--r--src/test/util_tests.cpp94
-rw-r--r--src/test/versionbits_tests.cpp116
-rw-r--r--src/threadinterrupt.cpp41
-rw-r--r--src/threadinterrupt.h34
-rw-r--r--src/timedata.cpp30
-rw-r--r--src/timedata.h16
-rw-r--r--src/tinyformat.h709
-rw-r--r--src/torcontrol.cpp144
-rw-r--r--src/txdb.cpp28
-rw-r--r--src/txdb.h14
-rw-r--r--src/txmempool.cpp274
-rw-r--r--src/txmempool.h192
-rw-r--r--src/ui_interface.cpp5
-rw-r--r--src/ui_interface.h7
-rw-r--r--src/uint256.cpp7
-rw-r--r--src/uint256.h11
-rw-r--r--src/undo.h28
-rw-r--r--src/univalue/.travis.yml2
-rw-r--r--src/univalue/include/univalue.h32
-rw-r--r--src/univalue/lib/univalue.cpp31
-rw-r--r--src/util.cpp359
-rw-r--r--src/util.h196
-rw-r--r--src/utilmoneystr.cpp8
-rw-r--r--src/utilstrencodings.cpp55
-rw-r--r--src/utilstrencodings.h5
-rw-r--r--src/utiltime.cpp30
-rw-r--r--src/utiltime.h13
-rw-r--r--src/validation.cpp (renamed from src/main.cpp)3919
-rw-r--r--src/validation.h (renamed from src/main.h)195
-rw-r--r--src/validationinterface.cpp35
-rw-r--r--src/validationinterface.h55
-rw-r--r--src/version.h9
-rw-r--r--src/versionbits.cpp37
-rw-r--r--src/versionbits.h4
-rw-r--r--src/wallet/coincontrol.h (renamed from src/coincontrol.h)16
-rw-r--r--src/wallet/crypter.cpp16
-rw-r--r--src/wallet/crypter.h23
-rw-r--r--src/wallet/db.cpp360
-rw-r--r--src/wallet/db.h145
-rw-r--r--src/wallet/feebumper.cpp284
-rw-r--r--src/wallet/feebumper.h56
-rw-r--r--src/wallet/rpcdump.cpp850
-rw-r--r--src/wallet/rpcwallet.cpp1874
-rw-r--r--src/wallet/rpcwallet.h15
-rw-r--r--src/wallet/test/accounting_tests.cpp36
-rw-r--r--src/wallet/test/crypto_tests.cpp48
-rw-r--r--src/wallet/test/rpc_wallet_tests.cpp229
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp7
-rw-r--r--src/wallet/test/wallet_tests.cpp270
-rw-r--r--src/wallet/wallet.cpp2271
-rw-r--r--src/wallet/wallet.h442
-rw-r--r--src/wallet/walletdb.cpp553
-rw-r--r--src/wallet/walletdb.h86
-rw-r--r--src/warnings.cpp89
-rw-r--r--src/warnings.h21
-rw-r--r--src/zmq/zmqnotificationinterface.cpp53
-rw-r--r--src/zmq/zmqnotificationinterface.h11
-rw-r--r--src/zmq/zmqpublishnotifier.cpp26
-rw-r--r--src/zmq/zmqpublishnotifier.h4
-rw-r--r--test/README.md99
-rw-r--r--test/functional/.gitignore (renamed from qa/rpc-tests/.gitignore)0
-rw-r--r--test/functional/README.md (renamed from qa/rpc-tests/README.md)2
-rwxr-xr-xtest/functional/abandonconflict.py (renamed from qa/rpc-tests/abandonconflict.py)64
-rwxr-xr-xtest/functional/assumevalid.py202
-rwxr-xr-xtest/functional/bip65-cltv-p2p.py (renamed from qa/rpc-tests/bip65-cltv-p2p.py)73
-rwxr-xr-xtest/functional/bip65-cltv.py (renamed from qa/rpc-tests/bip65-cltv.py)23
-rwxr-xr-xtest/functional/bip68-112-113-p2p.py (renamed from qa/rpc-tests/bip68-112-113-p2p.py)33
-rwxr-xr-xtest/functional/bip68-sequence.py (renamed from qa/rpc-tests/bip68-sequence.py)101
-rwxr-xr-xtest/functional/bip9-softforks.py (renamed from qa/rpc-tests/bip9-softforks.py)65
-rwxr-xr-xtest/functional/bipdersig-p2p.py (renamed from qa/rpc-tests/bipdersig-p2p.py)79
-rwxr-xr-xtest/functional/bipdersig.py (renamed from qa/rpc-tests/bipdersig.py)20
-rwxr-xr-xtest/functional/blockchain.py (renamed from qa/rpc-tests/blockchain.py)51
-rwxr-xr-xtest/functional/bumpfee.py303
-rwxr-xr-xtest/functional/combine_logs.py114
-rw-r--r--test/functional/combined_log_template.html40
-rw-r--r--test/functional/config.ini.in18
-rwxr-xr-xtest/functional/create_cache.py (renamed from qa/rpc-tests/create_cache.py)19
-rwxr-xr-xtest/functional/decodescript.py (renamed from qa/rpc-tests/decodescript.py)8
-rwxr-xr-xtest/functional/disablewallet.py37
-rwxr-xr-xtest/functional/disconnect_ban.py111
-rwxr-xr-xtest/functional/forknotify.py (renamed from qa/rpc-tests/forknotify.py)29
-rwxr-xr-xtest/functional/fundrawtransaction.py (renamed from qa/rpc-tests/fundrawtransaction.py)209
-rwxr-xr-xtest/functional/getblocktemplate_longpoll.py (renamed from qa/rpc-tests/getblocktemplate_longpoll.py)11
-rwxr-xr-xtest/functional/getblocktemplate_proposals.py (renamed from qa/rpc-tests/getblocktemplate_proposals.py)12
-rwxr-xr-xtest/functional/getchaintips.py (renamed from qa/rpc-tests/getchaintips.py)11
-rwxr-xr-xtest/functional/httpbasics.py (renamed from qa/rpc-tests/httpbasics.py)7
-rwxr-xr-xtest/functional/import-rescan.py192
-rwxr-xr-xtest/functional/importmulti.py452
-rwxr-xr-xtest/functional/importprunedfunds.py (renamed from qa/rpc-tests/importprunedfunds.py)59
-rwxr-xr-xtest/functional/invalidateblock.py (renamed from qa/rpc-tests/invalidateblock.py)44
-rwxr-xr-xtest/functional/invalidblockrequest.py (renamed from qa/rpc-tests/invalidblockrequest.py)17
-rwxr-xr-xtest/functional/invalidtxrequest.py (renamed from qa/rpc-tests/invalidtxrequest.py)7
-rwxr-xr-xtest/functional/keypool.py88
-rwxr-xr-xtest/functional/listsinceblock.py79
-rwxr-xr-xtest/functional/listtransactions.py (renamed from qa/rpc-tests/listtransactions.py)9
-rwxr-xr-xtest/functional/maxuploadtarget.py (renamed from qa/rpc-tests/maxuploadtarget.py)160
-rwxr-xr-xtest/functional/mempool_limit.py (renamed from qa/rpc-tests/mempool_limit.py)24
-rwxr-xr-xtest/functional/mempool_packages.py (renamed from qa/rpc-tests/mempool_packages.py)57
-rwxr-xr-xtest/functional/mempool_persist.py90
-rwxr-xr-xtest/functional/mempool_reorg.py (renamed from qa/rpc-tests/mempool_reorg.py)36
-rwxr-xr-xtest/functional/mempool_resurrect_test.py (renamed from qa/rpc-tests/mempool_resurrect_test.py)13
-rwxr-xr-xtest/functional/mempool_spendcoinbase.py (renamed from qa/rpc-tests/mempool_spendcoinbase.py)27
-rwxr-xr-xtest/functional/merkle_blocks.py (renamed from qa/rpc-tests/merkle_blocks.py)18
-rwxr-xr-xtest/functional/multi_rpc.py (renamed from qa/rpc-tests/multi_rpc.py)12
-rwxr-xr-xtest/functional/net.py93
-rwxr-xr-xtest/functional/nulldummy.py132
-rwxr-xr-xtest/functional/p2p-acceptblock.py (renamed from qa/rpc-tests/p2p-acceptblock.py)123
-rwxr-xr-xtest/functional/p2p-compactblocks.py945
-rwxr-xr-xtest/functional/p2p-feefilter.py (renamed from qa/rpc-tests/p2p-feefilter.py)45
-rwxr-xr-xtest/functional/p2p-fullblocktest.py (renamed from qa/rpc-tests/p2p-fullblocktest.py)49
-rwxr-xr-xtest/functional/p2p-leaktests.py133
-rwxr-xr-xtest/functional/p2p-mempool.py39
-rwxr-xr-xtest/functional/p2p-segwit.py (renamed from qa/rpc-tests/p2p-segwit.py)614
-rwxr-xr-xtest/functional/p2p-timeouts.py85
-rwxr-xr-xtest/functional/p2p-versionbits-warning.py (renamed from qa/rpc-tests/p2p-versionbits-warning.py)96
-rwxr-xr-xtest/functional/preciousblock.py115
-rwxr-xr-xtest/functional/prioritise_transaction.py (renamed from qa/rpc-tests/prioritise_transaction.py)68
-rwxr-xr-xtest/functional/proxy_test.py (renamed from qa/rpc-tests/proxy_test.py)45
-rwxr-xr-xtest/functional/pruning.py (renamed from qa/rpc-tests/pruning.py)294
-rwxr-xr-xtest/functional/rawtransactions.py (renamed from qa/rpc-tests/rawtransactions.py)69
-rwxr-xr-xtest/functional/receivedby.py (renamed from qa/rpc-tests/receivedby.py)9
-rwxr-xr-xtest/functional/reindex.py (renamed from qa/rpc-tests/reindex.py)28
-rwxr-xr-xtest/functional/replace-by-fee.py (renamed from qa/rpc-tests/replace-by-fee.py)158
-rwxr-xr-xtest/functional/rest.py (renamed from qa/rpc-tests/rest.py)26
-rwxr-xr-xtest/functional/rpcbind_test.py112
-rwxr-xr-xtest/functional/rpcnamedargs.py41
-rwxr-xr-xtest/functional/segwit.py638
-rwxr-xr-xtest/functional/sendheaders.py (renamed from qa/rpc-tests/sendheaders.py)220
-rwxr-xr-xtest/functional/signmessages.py (renamed from qa/rpc-tests/signmessages.py)8
-rwxr-xr-xtest/functional/signrawtransactions.py (renamed from qa/rpc-tests/signrawtransactions.py)45
-rwxr-xr-xtest/functional/smartfees.py (renamed from qa/rpc-tests/smartfees.py)127
-rw-r--r--test/functional/test_framework/__init__.py (renamed from qa/rpc-tests/test_framework/__init__.py)0
-rw-r--r--test/functional/test_framework/address.py69
-rw-r--r--test/functional/test_framework/authproxy.py (renamed from qa/rpc-tests/test_framework/authproxy.py)102
-rw-r--r--test/functional/test_framework/bignum.py (renamed from qa/rpc-tests/test_framework/bignum.py)10
-rw-r--r--test/functional/test_framework/blockstore.py (renamed from qa/rpc-tests/test_framework/blockstore.py)27
-rw-r--r--test/functional/test_framework/blocktools.py (renamed from qa/rpc-tests/test_framework/blocktools.py)13
-rwxr-xr-xtest/functional/test_framework/comptool.py (renamed from qa/rpc-tests/test_framework/comptool.py)75
-rw-r--r--test/functional/test_framework/coverage.py (renamed from qa/rpc-tests/test_framework/coverage.py)13
-rw-r--r--test/functional/test_framework/key.py (renamed from qa/rpc-tests/test_framework/key.py)35
-rwxr-xr-xtest/functional/test_framework/mininode.py (renamed from qa/rpc-tests/test_framework/mininode.py)741
-rw-r--r--test/functional/test_framework/netutil.py (renamed from qa/rpc-tests/test_framework/netutil.py)7
-rw-r--r--test/functional/test_framework/script.py (renamed from qa/rpc-tests/test_framework/script.py)14
-rw-r--r--test/functional/test_framework/siphash.py63
-rw-r--r--test/functional/test_framework/socks5.py (renamed from qa/rpc-tests/test_framework/socks5.py)22
-rwxr-xr-xtest/functional/test_framework/test_framework.py372
-rw-r--r--test/functional/test_framework/util.py (renamed from qa/rpc-tests/test_framework/util.py)347
-rwxr-xr-xtest/functional/test_runner.py500
-rwxr-xr-xtest/functional/txn_clone.py (renamed from qa/rpc-tests/txn_clone.py)9
-rwxr-xr-xtest/functional/txn_doublespend.py (renamed from qa/rpc-tests/txn_doublespend.py)9
-rwxr-xr-xtest/functional/wallet-accounts.py137
-rwxr-xr-xtest/functional/wallet-dump.py109
-rwxr-xr-xtest/functional/wallet-hd.py (renamed from qa/rpc-tests/wallet-hd.py)49
-rwxr-xr-xtest/functional/wallet.py (renamed from qa/rpc-tests/wallet.py)118
-rwxr-xr-xtest/functional/walletbackup.py (renamed from qa/rpc-tests/walletbackup.py)29
-rwxr-xr-xtest/functional/zapwallettxes.py (renamed from qa/rpc-tests/zapwallettxes.py)19
-rwxr-xr-xtest/functional/zmq_test.py (renamed from qa/rpc-tests/zmq_test.py)36
-rw-r--r--test/util/bctest.py139
-rwxr-xr-xtest/util/bitcoin-util-test.py36
-rw-r--r--test/util/buildenv.py.in4
-rw-r--r--test/util/data/bitcoin-util-test.json392
-rw-r--r--test/util/data/blanktxv1.hex (renamed from src/test/data/blanktx.hex)0
-rw-r--r--test/util/data/blanktxv1.json13
-rw-r--r--test/util/data/blanktxv2.hex1
-rw-r--r--test/util/data/blanktxv2.json13
-rw-r--r--test/util/data/tt-delin1-out.hex (renamed from src/test/data/tt-delin1-out.hex)0
-rw-r--r--test/util/data/tt-delin1-out.json219
-rw-r--r--test/util/data/tt-delout1-out.hex (renamed from src/test/data/tt-delout1-out.hex)0
-rw-r--r--test/util/data/tt-delout1-out.json215
-rw-r--r--test/util/data/tt-locktime317000-out.hex (renamed from src/test/data/tt-locktime317000-out.hex)0
-rw-r--r--test/util/data/tt-locktime317000-out.json228
-rw-r--r--test/util/data/tx394b54bb.hex (renamed from src/test/data/tx394b54bb.hex)0
-rw-r--r--test/util/data/txcreate1.hex (renamed from src/test/data/txcreate1.hex)2
-rw-r--r--test/util/data/txcreate1.json66
-rw-r--r--test/util/data/txcreate2.hex1
-rw-r--r--test/util/data/txcreate2.json22
-rw-r--r--test/util/data/txcreatedata1.hex (renamed from src/test/data/txcreatedata1.hex)2
-rw-r--r--test/util/data/txcreatedata1.json44
-rw-r--r--test/util/data/txcreatedata2.hex (renamed from src/test/data/txcreatedata2.hex)2
-rw-r--r--test/util/data/txcreatedata2.json44
-rw-r--r--test/util/data/txcreatedata_seq0.hex (renamed from src/test/data/txcreatedata_seq0.hex)2
-rw-r--r--test/util/data/txcreatedata_seq0.json35
-rw-r--r--test/util/data/txcreatedata_seq1.hex (renamed from src/test/data/txcreatedata_seq1.hex)0
-rw-r--r--test/util/data/txcreatedata_seq1.json44
-rw-r--r--test/util/data/txcreatemultisig1.hex1
-rw-r--r--test/util/data/txcreatemultisig1.json28
-rw-r--r--test/util/data/txcreatemultisig2.hex1
-rw-r--r--test/util/data/txcreatemultisig2.json26
-rw-r--r--test/util/data/txcreatemultisig3.hex1
-rw-r--r--test/util/data/txcreatemultisig3.json22
-rw-r--r--test/util/data/txcreatemultisig4.hex1
-rw-r--r--test/util/data/txcreatemultisig4.json26
-rw-r--r--test/util/data/txcreateoutpubkey1.hex1
-rw-r--r--test/util/data/txcreateoutpubkey1.json26
-rw-r--r--test/util/data/txcreateoutpubkey2.hex1
-rw-r--r--test/util/data/txcreateoutpubkey2.json22
-rw-r--r--test/util/data/txcreateoutpubkey3.hex1
-rw-r--r--test/util/data/txcreateoutpubkey3.json26
-rw-r--r--test/util/data/txcreatescript1.hex1
-rw-r--r--test/util/data/txcreatescript1.json22
-rw-r--r--test/util/data/txcreatescript2.hex1
-rw-r--r--test/util/data/txcreatescript2.json26
-rw-r--r--test/util/data/txcreatescript3.hex1
-rw-r--r--test/util/data/txcreatescript3.json22
-rw-r--r--test/util/data/txcreatescript4.hex1
-rw-r--r--test/util/data/txcreatescript4.json26
-rw-r--r--test/util/data/txcreatesignv1.hex (renamed from src/test/data/txcreatesign.hex)0
-rw-r--r--test/util/data/txcreatesignv1.json35
-rw-r--r--test/util/data/txcreatesignv2.hex1
924 files changed, 99710 insertions, 32483 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000000..28c1814998
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,37 @@
+<!--- Remove sections that do not apply -->
+
+This issue tracker is only for technical issues related to bitcoin-core.
+
+General bitcoin questions and/or support requests and are best directed to the [Bitcoin StackExchange](https://bitcoin.stackexchange.com).
+
+For reporting security issues, please read instructions at [https://bitcoincore.org/en/contact/](https://bitcoincore.org/en/contact/).
+
+### Describe the issue
+
+### Can you reliably reproduce the issue?
+#### If so, please list the steps to reproduce below:
+1.
+2.
+3.
+
+### Expected behaviour
+Tell us what should happen
+
+### Actual behaviour
+Tell us what happens instead
+
+### Screenshots.
+If the issue is related to the GUI, screenshots can be added to this issue via drag & drop.
+
+### What version of bitcoin-core are you using?
+List the version number/commit ID, and if it is an official binary, self compiled or a distribution package such as PPA.
+
+### Machine specs:
+- OS:
+- CPU:
+- RAM:
+- Disk size:
+- Disk Type (HD/SDD):
+
+### Any extra information that might be useful in the debugging process.
+This is normally the contents of a `debug.log` or `config.log` file. Raw text or a link to a pastebin type site are preferred.
diff --git a/.gitignore b/.gitignore
index ce40019dc3..f1e9ca20c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ src/bitcoind
src/bitcoin-cli
src/bitcoin-tx
src/test/test_bitcoin
+src/test/test_bitcoin_fuzzy
src/qt/test/test_bitcoin-qt
# autoreconf
@@ -55,7 +56,6 @@ src/qt/test/moc*.cpp
*.o
*.o-*
*.patch
-.bitcoin
*.a
*.pb.cc
*.pb.h
@@ -101,13 +101,9 @@ coverage_percent.txt
linux-coverage-build
linux-build
win32-build
-qa/pull-tester/run-bitcoind-for-test.sh
-qa/pull-tester/tests_config.py
-qa/pull-tester/cache/*
-qa/pull-tester/test.*/*
-qa/tmp
-cache/
-share/BitcoindComparisonTool.jar
+test/functional/config.ini
+test/util/buildenv.py
+test/cache/*
!src/leveldb*/Makefile
diff --git a/.travis.yml b/.travis.yml
index a6c51753b6..97bb475e4b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,5 @@
sudo: required
dist: trusty
-
-#workaround for https://github.com/travis-ci/travis-ci/issues/5227
-addons:
- hostname: bitcoin-tester
-
os: linux
language: generic
cache:
@@ -29,33 +24,38 @@ env:
# ARM
- HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="NO_QT=1" CHECK_DOC=1 GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
# Win32
- - HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-i686 wine1.6 bc openjdk-7-jre-headless" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports"
+ - HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-i686 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports"
# 32-bit + dash
- - HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc python3-zmq openjdk-7-jre-headless" DEP_OPTS="NO_QT=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash"
+ - HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc python3-zmq" DEP_OPTS="NO_QT=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash"
# Win64
- - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine1.6 bc openjdk-7-jre-headless" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports"
+ - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports"
# bitcoind
- - HOST=x86_64-unknown-linux-gnu PACKAGES="bc python3-zmq openjdk-7-jre-headless" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER"
+ - HOST=x86_64-unknown-linux-gnu PACKAGES="bc python3-zmq" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER"
# No wallet
- - HOST=x86_64-unknown-linux-gnu PACKAGES=" openjdk-7-jre-headless python3" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
+ - HOST=x86_64-unknown-linux-gnu PACKAGES="python3 xvfb" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
# Cross-Mac
- - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy"
+ - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy"
before_install:
- export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g")
install:
- - if [ -n "$PPA" ]; then travis_retry sudo add-apt-repository "$PPA" -y; fi
- if [ -n "$DPKG_ADD_ARCH" ]; then sudo dpkg --add-architecture "$DPKG_ADD_ARCH" ; fi
- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi
- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi
before_script:
+ - if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then contrib/devtools/commit-script-check.sh $TRAVIS_COMMIT_RANGE; fi
- unset CC; unset CXX
- if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/check-doc.py; fi
- mkdir -p depends/SDKs depends/sdk-sources
- if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
- if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
- make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS
+ # Start xvfb if needed, as documented at https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI
+ - if [ "$RUN_TESTS" = "true" -a "${DEP_OPTS#*NO_QT=1}" = "$DEP_OPTS" ]; then export DISPLAY=:99.0; /sbin/start-stop-daemon --start --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac; fi
script:
+ - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then while read LINE; do travis_retry gpg --keyserver hkp://subset.pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys; fi
+ - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then git fetch --unshallow; fi
+ - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then contrib/verify-commits/verify-commits.sh; fi
- export TRAVIS_COMMIT_LOG=`git log --format=fuller -1`
- if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi
- OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST
@@ -63,11 +63,15 @@ script:
- depends/$HOST/native/bin/ccache --max-size=$CCACHE_SIZE
- test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh
- mkdir build && cd build
- - ../configure $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false)
+ - ../configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false)
+ - make distdir VERSION=$HOST
+ - cd bitcoin-$HOST
+ - ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false)
- make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false )
- export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib
- if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS check VERBOSE=1; fi
- - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py --coverage; fi
+ - if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then extended="--extended --exclude pruning"; fi
+ - if [ "$RUN_TESTS" = "true" ]; then test/functional/test_runner.py --coverage --quiet ${extended}; fi
after_script:
- echo $TRAVIS_COMMIT_RANGE
- echo $TRAVIS_COMMIT_LOG
diff --git a/.tx/config b/.tx/config
index 3ce2ae71d0..c4eb6d831f 100644
--- a/.tx/config
+++ b/.tx/config
@@ -1,7 +1,7 @@
[main]
host = https://www.transifex.com
-[bitcoin.qt-translation-013x]
+[bitcoin.qt-translation-014x]
file_filter = src/qt/locale/bitcoin_<lang>.ts
source_file = src/qt/locale/bitcoin_en.ts
source_lang = en
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5c1138b812..f5d63517b1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,15 +1,26 @@
Contributing to Bitcoin Core
============================
-The Bitcoin Core project operates an open contributor model where anyone is welcome to contribute towards development in the form of peer review, testing and patches. This document explains the practical process and guidelines for contributing.
+The Bitcoin Core project operates an open contributor model where anyone is
+welcome to contribute towards development in the form of peer review, testing
+and patches. This document explains the practical process and guidelines for
+contributing.
-Firstly in terms of structure, there is no particular concept of “Core developers” in the sense of privileged people. Open source often naturally revolves around meritocracy where longer term contributors gain more trust from the developer community. However, some hierarchy is necessary for practical purposes. As such there are repository “maintainers” who are responsible for merging pull requests as well as a “lead maintainer” who is responsible for the release cycle, overall merging, moderation and appointment of maintainers.
+Firstly in terms of structure, there is no particular concept of "Core
+developers" in the sense of privileged people. Open source often naturally
+revolves around meritocracy where longer term contributors gain more trust from
+the developer community. However, some hierarchy is necessary for practical
+purposes. As such there are repository "maintainers" who are responsible for
+merging pull requests as well as a "lead maintainer" who is responsible for the
+release cycle, overall merging, moderation and appointment of maintainers.
Contributor Workflow
--------------------
-The codebase is maintained using the “contributor workflow” where everyone without exception contributes patch proposals using “pull requests”. This facilitates social contribution, easy testing and peer review.
+The codebase is maintained using the "contributor workflow" where everyone
+without exception contributes patch proposals using "pull requests". This
+facilitates social contribution, easy testing and peer review.
To contribute a patch, the workflow is as follows:
@@ -17,35 +28,77 @@ To contribute a patch, the workflow is as follows:
- Create topic branch
- Commit patches
-The project coding conventions in the [developer notes](doc/developer-notes.md) must be adhered to.
+The project coding conventions in the [developer notes](doc/developer-notes.md)
+must be adhered to.
-In general [commits should be atomic](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention) and diffs should be easy to read. For this reason do not mix any formatting fixes or code moves with actual code changes.
+In general [commits should be atomic](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention)
+and diffs should be easy to read. For this reason do not mix any formatting
+fixes or code moves with actual code changes.
-Commit messages should be verbose by default consisting of a short subject line (50 chars max), a blank line and detailed explanatory text as separate paragraph(s); unless the title alone is self-explanatory (like "Corrected typo in main.cpp") then a single title line is sufficient. Commit messages should be helpful to people reading your code in the future, so explain the reasoning for your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/).
+Commit messages should be verbose by default consisting of a short subject line
+(50 chars max), a blank line and detailed explanatory text as separate
+paragraph(s), unless the title alone is self-explanatory (like "Corrected typo
+in init.cpp") in which case a single title line is sufficient. Commit messages should be
+helpful to people reading your code in the future, so explain the reasoning for
+your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/).
-If a particular commit references another issue, please add the reference, for example `refs #1234`, or `fixes #4321`. Using the `fixes` or `closes` keywords will cause the corresponding issue to be closed when the pull request is merged.
+If a particular commit references another issue, please add the reference, for
+example `refs #1234`, or `fixes #4321`. Using the `fixes` or `closes` keywords
+will cause the corresponding issue to be closed when the pull request is merged.
-Please refer to the [Git manual](https://git-scm.com/doc) for more information about Git.
+Please refer to the [Git manual](https://git-scm.com/doc) for more information
+about Git.
- Push changes to your fork
- Create pull request
-The title of the pull request should be prefixed by the component or area that the pull request affects. Examples:
+The title of the pull request should be prefixed by the component or area that
+the pull request affects. Valid areas as:
+
+ - *Consensus* for changes to consensus critical code
+ - *Docs* for changes to the documentation
+ - *Qt* for changes to bitcoin-qt
+ - *Mining* for changes to the mining code
+ - *Net* or *P2P* for changes to the peer-to-peer network code
+ - *RPC/REST/ZMQ* for changes to the RPC, REST or ZMQ APIs
+ - *Scripts and tools* for changes to the scripts and tools
+ - *Tests* for changes to the bitcoin unit tests or QA tests
+ - *Trivial* should **only** be used for PRs that do not change generated
+ executable code. Notably, refactors (change of function arguments and code
+ reorganization) and changes in behavior should **not** be marked as trivial.
+ Examples of trivial PRs are changes to:
+ - comments
+ - whitespace
+ - variable names
+ - logging and messages
+ - *Utils and libraries* for changes to the utils and libraries
+ - *Wallet* for changes to the wallet code
+
+Examples:
Consensus: Add new opcode for BIP-XXXX OP_CHECKAWESOMESIG
Net: Automatically create hidden service, listen on Tor
Qt: Add feed bump button
- Trivial: Fix typo in main.cpp
+ Trivial: Fix typo in init.cpp
-If a pull request is specifically not to be considered for merging (yet) please prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists) in the body of the pull request to indicate tasks are pending.
+If a pull request is specifically not to be considered for merging (yet) please
+prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists)
+in the body of the pull request to indicate tasks are pending.
-The body of the pull request should contain enough description about what the patch does together with any justification/reasoning. You should include references to any discussions (for example other tickets or mailing list discussions).
+The body of the pull request should contain enough description about what the
+patch does together with any justification/reasoning. You should include
+references to any discussions (for example other tickets or mailing list
+discussions).
-At this stage one should expect comments and review from other contributors. You can add more commits to your pull request by committing them locally and pushing to your fork until you have satisfied all feedback.
+At this stage one should expect comments and review from other contributors. You
+can add more commits to your pull request by committing them locally and pushing
+to your fork until you have satisfied all feedback.
Squashing Commits
---------------------------
-If your pull request is accepted for merging, you may be asked by a maintainer to squash and or [rebase](https://git-scm.com/docs/git-rebase) your commits before it will be merged. The basic squashing workflow is shown below.
+If your pull request is accepted for merging, you may be asked by a maintainer
+to squash and or [rebase](https://git-scm.com/docs/git-rebase) your commits
+before it will be merged. The basic squashing workflow is shown below.
git checkout your_branch_name
git rebase -i HEAD~n
@@ -55,70 +108,164 @@ If your pull request is accepted for merging, you may be asked by a maintainer t
# save and quit
git push -f # (force push to GitHub)
-The length of time required for peer review is unpredictable and will vary from pull request to pull request.
+If you have problems with squashing (or other workflows with `git`), you can
+alternatively enable "Allow edits from maintainers" in the right GitHub
+sidebar and ask for help in the pull request.
+
+Please refrain from creating several pull requests for the same change.
+Use the pull request that is already open (or was created earlier) to amend
+changes. This preserves the discussion and review that happened earlier for
+the respective change set.
+
+The length of time required for peer review is unpredictable and will vary from
+pull request to pull request.
Pull Request Philosophy
-----------------------
-Patchsets should always be focused. For example, a pull request could add a feature, fix a bug, or refactor code; but not a mixture. Please also avoid super pull requests which attempt to do too much, are overly large, or overly complex as this makes review difficult.
+Patchsets should always be focused. For example, a pull request could add a
+feature, fix a bug, or refactor code; but not a mixture. Please also avoid super
+pull requests which attempt to do too much, are overly large, or overly complex
+as this makes review difficult.
-###Features
+### Features
-When adding a new feature, thought must be given to the long term technical debt and maintenance that feature may require after inclusion. Before proposing a new feature that will require maintenance, please consider if you are willing to maintain it (including bug fixing). If features get orphaned with no maintainer in the future, they may be removed by the Repository Maintainer.
+When adding a new feature, thought must be given to the long term technical debt
+and maintenance that feature may require after inclusion. Before proposing a new
+feature that will require maintenance, please consider if you are willing to
+maintain it (including bug fixing). If features get orphaned with no maintainer
+in the future, they may be removed by the Repository Maintainer.
-###Refactoring
+### Refactoring
-Refactoring is a necessary part of any software project's evolution. The following guidelines cover refactoring pull requests for the project.
+Refactoring is a necessary part of any software project's evolution. The
+following guidelines cover refactoring pull requests for the project.
-There are three categories of refactoring, code only moves, code style fixes, code refactoring. In general refactoring pull requests should not mix these three kinds of activity in order to make refactoring pull requests easy to review and uncontroversial. In all cases, refactoring PRs must not change the behaviour of code within the pull request (bugs must be preserved as is).
+There are three categories of refactoring, code only moves, code style fixes,
+code refactoring. In general refactoring pull requests should not mix these
+three kinds of activity in order to make refactoring pull requests easy to
+review and uncontroversial. In all cases, refactoring PRs must not change the
+behaviour of code within the pull request (bugs must be preserved as is).
-Project maintainers aim for a quick turnaround on refactoring pull requests, so where possible keep them short, uncomplex and easy to verify.
+Project maintainers aim for a quick turnaround on refactoring pull requests, so
+where possible keep them short, uncomplex and easy to verify.
"Decision Making" Process
-------------------------
-The following applies to code changes to the Bitcoin Core project (and related projects such as libsecp256k1), and is not to be confused with overall Bitcoin Network Protocol consensus changes.
+The following applies to code changes to the Bitcoin Core project (and related
+projects such as libsecp256k1), and is not to be confused with overall Bitcoin
+Network Protocol consensus changes.
-Whether a pull request is merged into Bitcoin Core rests with the project merge maintainers and ultimately the project lead.
+Whether a pull request is merged into Bitcoin Core rests with the project merge
+maintainers and ultimately the project lead.
-Maintainers will take into consideration if a patch is in line with the general principles of the project; meets the minimum standards for inclusion; and will judge the general consensus of contributors.
+Maintainers will take into consideration if a patch is in line with the general
+principles of the project; meets the minimum standards for inclusion; and will
+judge the general consensus of contributors.
In general, all pull requests must:
- - have a clear use case, fix a demonstrable bug or serve the greater good of the project (for example refactoring for modularisation);
+ - have a clear use case, fix a demonstrable bug or serve the greater good of
+ the project (for example refactoring for modularisation);
- be well peer reviewed;
- have unit tests and functional tests where appropriate;
- follow code style guidelines;
- not break the existing test suite;
- - where bugs are fixed, where possible, there should be unit tests demonstrating the bug and also proving the fix. This helps prevent regression.
+ - where bugs are fixed, where possible, there should be unit tests
+ demonstrating the bug and also proving the fix. This helps prevent regression.
-Patches that change Bitcoin consensus rules are considerably more involved than normal because they affect the entire ecosystem and so must be preceded by extensive mailing list discussions and have a numbered BIP. While each case will be different, one should be prepared to expend more time and effort than for other kinds of patches because of increased peer review and consensus building requirements.
+Patches that change Bitcoin consensus rules are considerably more involved than
+normal because they affect the entire ecosystem and so must be preceded by
+extensive mailing list discussions and have a numbered BIP. While each case will
+be different, one should be prepared to expend more time and effort than for
+other kinds of patches because of increased peer review and consensus building
+requirements.
-###Peer Review
+### Peer Review
-Anyone may participate in peer review which is expressed by comments in the pull request. Typically reviewers will review the code for obvious errors, as well as test out the patch set and opine on the technical merits of the patch. Project maintainers take into account the peer review when determining if there is consensus to merge a pull request (remember that discussions may have been spread out over github, mailing list and IRC discussions). The following language is used within pull-request comments:
+Anyone may participate in peer review which is expressed by comments in the pull
+request. Typically reviewers will review the code for obvious errors, as well as
+test out the patch set and opine on the technical merits of the patch. Project
+maintainers take into account the peer review when determining if there is
+consensus to merge a pull request (remember that discussions may have been
+spread out over GitHub, mailing list and IRC discussions). The following
+language is used within pull-request comments:
- ACK means "I have tested the code and I agree it should be merged";
- - NACK means "I disagree this should be merged", and must be accompanied by sound technical justification. NACKs without accompanying reasoning may be disregarded;
- - utACK means "I have not tested the code, but I have reviewed it and it looks OK, I agree it can be merged";
+ - NACK means "I disagree this should be merged", and must be accompanied by
+ sound technical justification (or in certain cases of copyright/patent/licensing
+ issues, legal justification). NACKs without accompanying reasoning may be
+ disregarded;
+ - utACK means "I have not tested the code, but I have reviewed it and it looks
+ OK, I agree it can be merged";
- Concept ACK means "I agree in the general principle of this pull request";
- Nit refers to trivial, often non-blocking issues.
Reviewers should include the commit hash which they reviewed in their comments.
-Project maintainers reserve the right to weigh the opinions of peer reviewers using common sense judgement and also may weight based on meritocracy: Those that have demonstrated a deeper commitment and understanding towards the project (over time) or have clear domain expertise may naturally have more weight, as one would expect in all walks of life.
-
-Where a patch set affects consensus critical code, the bar will be set much higher in terms of discussion and peer review requirements, keeping in mind that mistakes could be very costly to the wider community. This includes refactoring of consensus critical code.
-
-Where a patch set proposes to change the Bitcoin consensus, it must have been discussed extensively on the mailing list and IRC, be accompanied by a widely discussed BIP and have a generally widely perceived technical consensus of being a worthwhile change based on the judgement of the maintainers.
+Project maintainers reserve the right to weigh the opinions of peer reviewers
+using common sense judgement and also may weight based on meritocracy: Those
+that have demonstrated a deeper commitment and understanding towards the project
+(over time) or have clear domain expertise may naturally have more weight, as
+one would expect in all walks of life.
+
+Where a patch set affects consensus critical code, the bar will be set much
+higher in terms of discussion and peer review requirements, keeping in mind that
+mistakes could be very costly to the wider community. This includes refactoring
+of consensus critical code.
+
+Where a patch set proposes to change the Bitcoin consensus, it must have been
+discussed extensively on the mailing list and IRC, be accompanied by a widely
+discussed BIP and have a generally widely perceived technical consensus of being
+a worthwhile change based on the judgement of the maintainers.
+
+### Finding Reviewers
+
+As most reviewers are themselves developers with their own projects, the review
+process can be quite lengthy, and some amount of patience is required. If you find
+that you've been waiting for a pull request to be given attention for several
+months, there may be a number of reasons for this, some of which you can do something
+about:
+
+ - It may be because of a feature freeze due to an upcoming release. During this time,
+ only bug fixes are taken into consideration. If your pull request is a new feature,
+ it will not be prioritized until the release is over. Wait for release.
+ - It may be because the changes you are suggesting do not appeal to people. Rather than
+ nits and critique, which require effort and means they care enough to spend time on your
+ contribution, thundering silence is a good sign of widespread (mild) dislike of a given change
+ (because people don't assume *others* won't actually like the proposal). Don't take
+ that personally, though! Instead, take another critical look at what you are suggesting
+ and see if it: changes too much, is too broad, doesn't adhere to the
+ [developer notes](doc/developer-notes.md), is dangerous or insecure, is messily written, etc.
+ Identify and address any of the issues you find. Then ask e.g. on IRC if someone could give
+ their opinion on the concept itself.
+ - It may be because your code is too complex for all but a few people. And those people
+ may not have realized your pull request even exists. A great way to find people who
+ are qualified and care about the code you are touching is the
+ [Git Blame feature](https://help.github.com/articles/tracing-changes-in-a-file/). Simply
+ find the person touching the code you are touching before you and see if you can find
+ them and give them a nudge. Don't be incessant about the nudging though.
+ - Finally, if all else fails, ask on IRC or elsewhere for someone to give your pull request
+ a look. If you think you've been waiting an unreasonably long amount of time (month+) for
+ no particular reason (few lines changed, etc), this is totally fine. Try to return the favor
+ when someone else is asking for feedback on their code, and universe balances out.
Release Policy
--------------
The project leader is the release manager for each Bitcoin Core release.
+
+Copyright
+---------
+
+By contributing to this repository, you agree to license your work under the
+MIT license unless specified otherwise in `contrib/debian/copyright` or at
+the top of the file itself. Any work contributed where you are not the original
+author must contain its license header with the original author(s) and source.
diff --git a/COPYING b/COPYING
index c6be8e5470..c6203c0f76 100644
--- a/COPYING
+++ b/COPYING
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2009-2016 The Bitcoin Core developers
+Copyright (c) 2009-2017 The Bitcoin Core developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index 07ee48427c..0000000000
--- a/INSTALL
+++ /dev/null
@@ -1,5 +0,0 @@
-Building Bitcoin
-
-See doc/build-*.md for instructions on building bitcoind,
-the intended-for-services, no-graphical-interface, reference
-implementation of Bitcoin. \ No newline at end of file
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 0000000000..520a47d960
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,5 @@
+Building Bitcoin
+================
+
+See doc/build-*.md for instructions on building the various
+elements of the Bitcoin Core reference implementation of Bitcoin.
diff --git a/Makefile.am b/Makefile.am
index b10d085066..3a56eea0c0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,12 @@
+# Copyright (c) 2013-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.
+
ACLOCAL_AMFLAGS = -I build-aux/m4
SUBDIRS = src
+if ENABLE_MAN
+SUBDIRS += doc/man
+endif
.PHONY: deploy FORCE
GZIP_ENV="-9n"
@@ -32,6 +39,11 @@ OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed
OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW
DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md)
+DIST_CONTRIB = $(top_srcdir)/contrib/bitcoin-cli.bash-completion \
+ $(top_srcdir)/contrib/bitcoin-tx.bash-completion \
+ $(top_srcdir)/contrib/bitcoind.bash-completion \
+ $(top_srcdir)/contrib/init \
+ $(top_srcdir)/contrib/rpm
BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \
$(top_srcdir)/contrib/devtools/security-check.py
@@ -47,9 +59,9 @@ OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \
$(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \
$(top_srcdir)/contrib/macdeploy/detached-sig-create.sh
-COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \
+COVERAGE_INFO = baseline_filtered_combined.info baseline.info \
leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \
- baseline_filtered.info block_test_filtered.info rpc_test.info rpc_test_filtered.info \
+ baseline_filtered.info functional_test.info functional_test_filtered.info \
leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info
dist-hook:
@@ -64,9 +76,6 @@ $(BITCOIN_WIN_INSTALLER): all-recursive
echo error: could not build $@
@echo built $@
-$(if $(findstring src/,$(MAKECMDGOALS)),$(MAKECMDGOALS), none): FORCE
- $(MAKE) -C src $(patsubst src/%,%,$@)
-
$(OSX_APP)/Contents/PkgInfo:
$(MKDIR_P) $(@D)
@echo "APPL????" > $@
@@ -99,9 +108,16 @@ osx_volname:
echo $(OSX_VOLNAME) >$@
if BUILD_DARWIN
-$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING)
+$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) $(OSX_BACKGROUND_IMAGE)
$(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME)
+$(OSX_BACKGROUND_IMAGE).png: contrib/macdeploy/$(OSX_BACKGROUND_SVG)
+ sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d 36 -p 36 -o $@
+$(OSX_BACKGROUND_IMAGE)@2x.png: contrib/macdeploy/$(OSX_BACKGROUND_SVG)
+ sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d 72 -p 72 -o $@
+$(OSX_BACKGROUND_IMAGE): $(OSX_BACKGROUND_IMAGE).png $(OSX_BACKGROUND_IMAGE)@2x.png
+ tiffutil -cathidpicheck $^ -out $@
+
deploydir: $(OSX_DMG)
else
APP_DIST_DIR=$(top_builddir)/dist
@@ -175,30 +191,20 @@ test_bitcoin.info: baseline_filtered_combined.info
test_bitcoin_filtered.info: test_bitcoin.info
$(LCOV) -r $< "/usr/include/*" -o $@
-block_test.info: test_bitcoin_filtered.info
- $(MKDIR_P) qa/tmp
- -@TIMEOUT=15 qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS)
- $(LCOV) -c -d $(abs_builddir)/src --t BitcoinJBlockTest -o $@
- $(LCOV) -z -d $(abs_builddir)/src
- $(LCOV) -z -d $(abs_builddir)/src/leveldb
-
-block_test_filtered.info: block_test.info
- $(LCOV) -r $< "/usr/include/*" -o $@
-
-rpc_test.info: test_bitcoin_filtered.info
- -@TIMEOUT=15 python qa/pull-tester/rpc-tests.py $(EXTENDED_RPC_TESTS)
- $(LCOV) -c -d $(abs_builddir)/src --t rpc-tests -o $@
+functional_test.info: test_bitcoin_filtered.info
+ -@TIMEOUT=15 python test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS)
+ $(LCOV) -c -d $(abs_builddir)/src --t functional-tests -o $@
$(LCOV) -z -d $(abs_builddir)/src
$(LCOV) -z -d $(abs_builddir)/src/leveldb
-rpc_test_filtered.info: rpc_test.info
+functional_test_filtered.info: functional_test.info
$(LCOV) -r $< "/usr/include/*" -o $@
test_bitcoin_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info
$(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@
-total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info block_test_filtered.info rpc_test_filtered.info
- $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a block_test_filtered.info -a rpc_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
+total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info functional_test_filtered.info
+ $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a functional_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info
$(GENHTML) -s $< -o $(@D)
@@ -212,23 +218,72 @@ cov: test_bitcoin.coverage/.dirstamp total.coverage/.dirstamp
endif
-if USE_COMPARISON_TOOL
-check-local:
- $(MKDIR_P) qa/tmp
- @qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS) 2>&1
-endif
-
dist_noinst_SCRIPTS = autogen.sh
-EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc-tests $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS)
+EXTRA_DIST = $(top_srcdir)/share/genbuild.sh test/functional/test_runner.py test/functional $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS)
+
+EXTRA_DIST += \
+ test/util/bctest.py \
+ test/util/bitcoin-util-test.py \
+ test/util/data/bitcoin-util-test.json \
+ test/util/data/blanktxv1.hex \
+ test/util/data/blanktxv1.json \
+ test/util/data/blanktxv2.hex \
+ test/util/data/blanktxv2.json \
+ test/util/data/tt-delin1-out.hex \
+ test/util/data/tt-delin1-out.json \
+ test/util/data/tt-delout1-out.hex \
+ test/util/data/tt-delout1-out.json \
+ test/util/data/tt-locktime317000-out.hex \
+ test/util/data/tt-locktime317000-out.json \
+ test/util/data/tx394b54bb.hex \
+ test/util/data/txcreate1.hex \
+ test/util/data/txcreate1.json \
+ test/util/data/txcreate2.hex \
+ test/util/data/txcreate2.json \
+ test/util/data/txcreatedata1.hex \
+ test/util/data/txcreatedata1.json \
+ test/util/data/txcreatedata2.hex \
+ test/util/data/txcreatedata2.json \
+ test/util/data/txcreatedata_seq0.hex \
+ test/util/data/txcreatedata_seq0.json \
+ test/util/data/txcreatedata_seq1.hex \
+ test/util/data/txcreatedata_seq1.json \
+ test/util/data/txcreatemultisig1.hex \
+ test/util/data/txcreatemultisig1.json \
+ test/util/data/txcreatemultisig2.hex \
+ test/util/data/txcreatemultisig2.json \
+ test/util/data/txcreatemultisig3.hex \
+ test/util/data/txcreatemultisig3.json \
+ test/util/data/txcreatemultisig4.hex \
+ test/util/data/txcreatemultisig4.json \
+ test/util/data/txcreateoutpubkey1.hex \
+ test/util/data/txcreateoutpubkey1.json \
+ test/util/data/txcreateoutpubkey2.hex \
+ test/util/data/txcreateoutpubkey2.json \
+ test/util/data/txcreateoutpubkey3.hex \
+ test/util/data/txcreateoutpubkey3.json \
+ test/util/data/txcreatescript1.hex \
+ test/util/data/txcreatescript1.json \
+ test/util/data/txcreatescript2.hex \
+ test/util/data/txcreatescript2.json \
+ test/util/data/txcreatescript3.hex \
+ test/util/data/txcreatescript3.json \
+ test/util/data/txcreatescript4.hex \
+ test/util/data/txcreatescript4.json \
+ test/util/data/txcreatesignv1.hex \
+ test/util/data/txcreatesignv1.json \
+ test/util/data/txcreatesignv2.hex
CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER)
# This file is problematic for out-of-tree builds if it exists.
-DISTCLEANFILES = qa/pull-tester/tests_config.pyc
+DISTCLEANFILES = test/util/buildenv.pyc
.INTERMEDIATE: $(COVERAGE_INFO)
+DISTCHECK_CONFIGURE_FLAGS = --enable-man
+
clean-local:
- rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ qa/tmp/ cache/ $(OSX_APP)
- rm -rf qa/pull-tester/__pycache__
+ rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ test/tmp/ cache/ $(OSX_APP)
+ rm -rf test/functional/__pycache__
diff --git a/README.md b/README.md
index 3c41649c1b..5db9fc9928 100644
--- a/README.md
+++ b/README.md
@@ -49,13 +49,14 @@ lots of money.
### Automated Testing
-Developers are strongly encouraged to write [unit tests](/doc/unit-tests.md) for new code, and to
+Developers are strongly encouraged to write [unit tests](src/test/README.md) for new code, and to
submit new unit tests for old code. Unit tests can be compiled and run
-(assuming they weren't disabled in configure) with: `make check`
+(assuming they weren't disabled in configure) with: `make check`. Further details on running
+and extending unit tests can be found in [/src/test/README.md](/src/test/README.md).
-There are also [regression and integration tests](/qa) of the RPC interface, written
+There are also [regression and integration tests](/test), written
in Python, that are run automatically on the build server.
-These tests can be run (if the [test dependencies](/qa) are installed) with: `qa/pull-tester/rpc-tests.py`
+These tests can be run (if the [test dependencies](/test) are installed) with: `test/functional/test_runner.py`
The Travis CI system makes sure that every pull request is built for Windows, Linux, and OS X, and that unit/sanity tests are run automatically.
diff --git a/autogen.sh b/autogen.sh
index 46e36ff5b2..27417daf76 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,4 +1,8 @@
#!/bin/sh
+# Copyright (c) 2013-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.
+
set -e
srcdir="$(dirname $0)"
cd "$srcdir"
diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4
index 45d948933d..650c94fa64 100644
--- a/build-aux/m4/ax_boost_base.m4
+++ b/build-aux/m4/ax_boost_base.m4
@@ -33,7 +33,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 26
+#serial 27
AC_DEFUN([AX_BOOST_BASE],
[
@@ -96,7 +96,7 @@ if test "x$want_boost" = "xyes"; then
libsubdirs="lib64 libx32 lib lib64"
;;
ppc64|s390x|sparc64|aarch64|ppc64le)
- libsubdirs="lib64 lib lib64 ppc64le"
+ libsubdirs="lib64 lib lib64"
;;
esac
diff --git a/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/build-aux/m4/ax_cxx_compile_stdcxx.m4
index 2c18e49c56..f147cee3b1 100644
--- a/build-aux/m4/ax_cxx_compile_stdcxx.m4
+++ b/build-aux/m4/ax_cxx_compile_stdcxx.m4
@@ -57,8 +57,14 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+ m4_if([$4], [], [ax_cxx_compile_cxx$1_try_default=true],
+ [$4], [default], [ax_cxx_compile_cxx$1_try_default=true],
+ [$4], [nodefault], [ax_cxx_compile_cxx$1_try_default=false],
+ [m4_fatal([invalid fourth argument `$4' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
+
+ m4_if([$4], [nodefault], [], [dnl
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
ax_cv_cxx_compile_cxx$1,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
@@ -66,7 +72,7 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
[ax_cv_cxx_compile_cxx$1=no])])
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
ac_success=yes
- fi
+ fi])
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
diff --git a/build-aux/m4/bitcoin_find_bdb48.m4 b/build-aux/m4/bitcoin_find_bdb48.m4
index 2aa493a6af..980f1e8f19 100644
--- a/build-aux/m4/bitcoin_find_bdb48.m4
+++ b/build-aux/m4/bitcoin_find_bdb48.m4
@@ -1,66 +1,78 @@
+dnl Copyright (c) 2013-2015 The Bitcoin Core developers
+dnl Distributed under the MIT software license, see the accompanying
+dnl file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
AC_DEFUN([BITCOIN_FIND_BDB48],[
- AC_MSG_CHECKING([for Berkeley DB C++ headers])
- BDB_CPPFLAGS=
- BDB_LIBS=
- bdbpath=X
- bdb48path=X
- bdbdirlist=
- for _vn in 4.8 48 4 5 ''; do
- for _pfx in b lib ''; do
- bdbdirlist="$bdbdirlist ${_pfx}db${_vn}"
+ AC_ARG_VAR(BDB_CFLAGS, [C compiler flags for BerkeleyDB, bypasses autodetection])
+ AC_ARG_VAR(BDB_LIBS, [Linker flags for BerkeleyDB, bypasses autodetection])
+
+ if test "x$BDB_CFLAGS" = "x"; then
+ AC_MSG_CHECKING([for Berkeley DB C++ headers])
+ BDB_CPPFLAGS=
+ bdbpath=X
+ bdb48path=X
+ bdbdirlist=
+ for _vn in 4.8 48 4 5 ''; do
+ for _pfx in b lib ''; do
+ bdbdirlist="$bdbdirlist ${_pfx}db${_vn}"
+ done
done
- done
- for searchpath in $bdbdirlist ''; do
- test -n "${searchpath}" && searchpath="${searchpath}/"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- #include <${searchpath}db_cxx.h>
- ]],[[
- #if !((DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || DB_VERSION_MAJOR > 4)
- #error "failed to find bdb 4.8+"
- #endif
- ]])],[
- if test "x$bdbpath" = "xX"; then
- bdbpath="${searchpath}"
- fi
- ],[
- continue
- ])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- #include <${searchpath}db_cxx.h>
- ]],[[
- #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 8)
- #error "failed to find bdb 4.8"
- #endif
- ]])],[
- bdb48path="${searchpath}"
- break
- ],[])
- done
- if test "x$bdbpath" = "xX"; then
- AC_MSG_RESULT([no])
- AC_MSG_ERROR([libdb_cxx headers missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)])
- elif test "x$bdb48path" = "xX"; then
- BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdbpath}],db_cxx)
- AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 4.8])],[
- AC_MSG_WARN([Found Berkeley DB other than 4.8; wallets opened by this build will not be portable!])
- ],[
- AC_MSG_ERROR([Found Berkeley DB other than 4.8, required for portable wallets (--with-incompatible-bdb to ignore or --disable-wallet to disable wallet functionality)])
- ])
+ for searchpath in $bdbdirlist ''; do
+ test -n "${searchpath}" && searchpath="${searchpath}/"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <${searchpath}db_cxx.h>
+ ]],[[
+ #if !((DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || DB_VERSION_MAJOR > 4)
+ #error "failed to find bdb 4.8+"
+ #endif
+ ]])],[
+ if test "x$bdbpath" = "xX"; then
+ bdbpath="${searchpath}"
+ fi
+ ],[
+ continue
+ ])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <${searchpath}db_cxx.h>
+ ]],[[
+ #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 8)
+ #error "failed to find bdb 4.8"
+ #endif
+ ]])],[
+ bdb48path="${searchpath}"
+ break
+ ],[])
+ done
+ if test "x$bdbpath" = "xX"; then
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([libdb_cxx headers missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)])
+ elif test "x$bdb48path" = "xX"; then
+ BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdbpath}],db_cxx)
+ AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 4.8])],[
+ AC_MSG_WARN([Found Berkeley DB other than 4.8; wallets opened by this build will not be portable!])
+ ],[
+ AC_MSG_ERROR([Found Berkeley DB other than 4.8, required for portable wallets (--with-incompatible-bdb to ignore or --disable-wallet to disable wallet functionality)])
+ ])
+ else
+ BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdb48path}],db_cxx)
+ bdbpath="${bdb48path}"
+ fi
else
- BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdb48path}],db_cxx)
- bdbpath="${bdb48path}"
+ BDB_CPPFLAGS=${BDB_CFLAGS}
fi
AC_SUBST(BDB_CPPFLAGS)
- # TODO: Ideally this could find the library version and make sure it matches the headers being used
- for searchlib in db_cxx-4.8 db_cxx; do
- AC_CHECK_LIB([$searchlib],[main],[
- BDB_LIBS="-l${searchlib}"
- break
- ])
- done
if test "x$BDB_LIBS" = "x"; then
- AC_MSG_ERROR([libdb_cxx missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)])
+ # TODO: Ideally this could find the library version and make sure it matches the headers being used
+ for searchlib in db_cxx-4.8 db_cxx; do
+ AC_CHECK_LIB([$searchlib],[main],[
+ BDB_LIBS="-l${searchlib}"
+ break
+ ])
+ done
+ if test "x$BDB_LIBS" = "x"; then
+ AC_MSG_ERROR([libdb_cxx missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)])
+ fi
fi
AC_SUBST(BDB_LIBS)
])
diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4
index d26136cbe9..1b339559fc 100644
--- a/build-aux/m4/bitcoin_qt.m4
+++ b/build-aux/m4/bitcoin_qt.m4
@@ -1,3 +1,7 @@
+dnl Copyright (c) 2013-2016 The Bitcoin Core developers
+dnl Distributed under the MIT software license, see the accompanying
+dnl file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
dnl Helper for cases where a qt dependency is not met.
dnl Output: If qt version is auto, set bitcoin_enable_qt to false. Else, exit.
AC_DEFUN([BITCOIN_QT_FAIL],[
@@ -126,6 +130,8 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
if test "x$bitcoin_cv_need_acc_widget" = "xyes"; then
_BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets])
fi
+ _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal])
+ AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists])
if test x$TARGET_OS = xwindows; then
_BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows])
AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows])
@@ -469,8 +475,8 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[
])
BITCOIN_QT_CHECK(AC_CHECK_LIB([z] ,[main],,AC_MSG_WARN([zlib not found. Assuming qt has it built-in])))
- BITCOIN_QT_CHECK(AC_CHECK_LIB([png] ,[main],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in])))
- BITCOIN_QT_CHECK(AC_CHECK_LIB([jpeg] ,[main],,AC_MSG_WARN([libjpeg not found. Assuming qt has it built-in])))
+ BITCOIN_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in])))
+ BITCOIN_QT_CHECK(AC_SEARCH_LIBS([jpeg_create_decompress] ,[qtjpeg jpeg],,AC_MSG_WARN([libjpeg not found. Assuming qt has it built-in])))
BITCOIN_QT_CHECK(AC_SEARCH_LIBS([pcre16_exec], [qtpcre pcre16],,AC_MSG_WARN([libpcre16 not found. Assuming qt has it built-in])))
BITCOIN_QT_CHECK(AC_SEARCH_LIBS([hb_ot_tags_from_script] ,[qtharfbuzzng harfbuzz],,AC_MSG_WARN([libharfbuzz not found. Assuming qt has it built-in or support is disabled])))
BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Core] ,[main],,BITCOIN_QT_FAIL(lib$QT_LIB_PREFIXCore not found)))
diff --git a/build-aux/m4/bitcoin_subdir_to_include.m4 b/build-aux/m4/bitcoin_subdir_to_include.m4
index 66f106c7d4..7841042ac8 100644
--- a/build-aux/m4/bitcoin_subdir_to_include.m4
+++ b/build-aux/m4/bitcoin_subdir_to_include.m4
@@ -1,3 +1,7 @@
+dnl Copyright (c) 2013-2014 The Bitcoin Core developers
+dnl Distributed under the MIT software license, see the accompanying
+dnl file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
dnl BITCOIN_SUBDIR_TO_INCLUDE([CPPFLAGS-VARIABLE-NAME],[SUBDIRECTORY-NAME],[HEADER-FILE])
dnl SUBDIRECTORY-NAME must end with a path separator
AC_DEFUN([BITCOIN_SUBDIR_TO_INCLUDE],[
diff --git a/build-aux/m4/l_atomic.m4 b/build-aux/m4/l_atomic.m4
new file mode 100644
index 0000000000..75c43f9a92
--- /dev/null
+++ b/build-aux/m4/l_atomic.m4
@@ -0,0 +1,46 @@
+dnl Copyright (c) 2015 Tim Kosse <tim.kosse@filezilla-project.org>
+dnl Copying and distribution of this file, with or without modification, are
+dnl permitted in any medium without royalty provided the copyright notice
+dnl and this notice are preserved. This file is offered as-is, without any
+dnl warranty.
+
+# Some versions of gcc/libstdc++ require linking with -latomic if
+# using the C++ atomic library.
+#
+# Sourced from http://bugs.debian.org/797228
+
+m4_define([_CHECK_ATOMIC_testbody], [[
+ #include <atomic>
+ #include <cstdint>
+
+ int main() {
+ std::atomic<int64_t> a{};
+
+ int64_t v = 5;
+ int64_t r = a.fetch_add(v);
+ return static_cast<int>(r);
+ }
+]])
+
+AC_DEFUN([CHECK_ATOMIC], [
+
+ AC_LANG_PUSH(C++)
+
+ AC_MSG_CHECKING([whether std::atomic can be used without link library])
+
+ AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[
+ AC_MSG_RESULT([yes])
+ ],[
+ AC_MSG_RESULT([no])
+ LIBS="$LIBS -latomic"
+ AC_MSG_CHECKING([whether std::atomic needs -latomic])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[
+ AC_MSG_RESULT([yes])
+ ],[
+ AC_MSG_RESULT([no])
+ AC_MSG_FAILURE([cannot figure out how to use std::atomic])
+ ])
+ ])
+
+ AC_LANG_POP
+])
diff --git a/configure.ac b/configure.ac
index 011af6bd1b..3672700488 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,15 +1,15 @@
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0)
-define(_CLIENT_VERSION_MINOR, 12)
+define(_CLIENT_VERSION_MINOR, 14)
define(_CLIENT_VERSION_REVISION, 99)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, false)
-define(_COPYRIGHT_YEAR, 2016)
+define(_COPYRIGHT_YEAR, 2017)
define(_COPYRIGHT_HOLDERS,[The %s developers])
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]])
AC_INIT([Bitcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/bitcoin/bitcoin/issues],[bitcoin],[https://bitcoincore.org/])
-AC_CONFIG_SRCDIR([src/main.cpp])
+AC_CONFIG_SRCDIR([src/validation.cpp])
AC_CONFIG_HEADERS([src/config/bitcoin-config.h])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
@@ -45,7 +45,6 @@ else
CXXFLAGS_overridden=no
fi
AC_PROG_CXX
-m4_ifdef([AC_PROG_OBJCXX],[AC_PROG_OBJCXX])
dnl By default, libtool for mingw refuses to link static libs into a dll for
dnl fear of mixing pic/non-pic objects, and import/export complications. Since
@@ -56,7 +55,19 @@ case $host in
;;
esac
dnl Require C++11 compiler (no GNU extensions)
-AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory])
+AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault])
+dnl Check if -latomic is required for <std::atomic>
+CHECK_ATOMIC
+
+dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures
+dnl that we get the same -std flags for both.
+m4_ifdef([AC_PROG_OBJCXX],[
+if test "x${OBJCXX+set}" = "x"; then
+ OBJCXX="${CXX}"
+fi
+AC_PROG_OBJCXX
+])
+
dnl Libtool init checks.
LT_INIT([pic-only])
@@ -66,8 +77,8 @@ AC_PATH_TOOL(RANLIB, ranlib)
AC_PATH_TOOL(STRIP, strip)
AC_PATH_TOOL(GCOV, gcov)
AC_PATH_PROG(LCOV, lcov)
-AC_PATH_PROG(JAVA, java)
-AC_PATH_PROGS([PYTHON], [python3 python2.7 python2 python])
+dnl Python 3.x is supported from 3.4 on (see https://github.com/bitcoin/bitcoin/issues/7893)
+AC_PATH_PROGS([PYTHON], [python3.6 python3.5 python3.4 python3 python2.7 python2 python])
AC_PATH_PROG(GENHTML, genhtml)
AC_PATH_PROG([GIT], [git])
AC_PATH_PROG(CCACHE,ccache)
@@ -113,20 +124,10 @@ AC_ARG_ENABLE(bench,
[use_bench=$enableval],
[use_bench=yes])
-AC_ARG_WITH([comparison-tool],
- AS_HELP_STRING([--with-comparison-tool],[path to java comparison tool (requires --enable-tests)]),
- [use_comparison_tool=$withval],
- [use_comparison_tool=no])
-
-AC_ARG_ENABLE([comparison-tool-reorg-tests],
- AS_HELP_STRING([--enable-comparison-tool-reorg-tests],[enable expensive reorg tests in the comparison tool (default no)]),
- [use_comparison_tool_reorg_tests=$enableval],
- [use_comparison_tool_reorg_tests=no])
-
-AC_ARG_ENABLE([extended-rpc-tests],
- AS_HELP_STRING([--enable-extended-rpc-tests],[enable expensive RPC tests when using lcov (default no)]),
- [use_extended_rpc_tests=$enableval],
- [use_extended_rpc_tests=no])
+AC_ARG_ENABLE([extended-functional-tests],
+ AS_HELP_STRING([--enable-extended-functional-tests],[enable expensive functional tests when using lcov (default no)]),
+ [use_extended_functional_tests=$enableval],
+ [use_extended_functional_tests=no])
AC_ARG_WITH([qrencode],
[AS_HELP_STRING([--with-qrencode],
@@ -178,6 +179,12 @@ AC_ARG_ENABLE([zmq],
AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], [])
+AC_ARG_ENABLE(man,
+ [AS_HELP_STRING([--disable-man],
+ [do not install man pages (default is to install)])],,
+ enable_man=yes)
+AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" != no)
+
# Enable debug
AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--enable-debug],
@@ -185,6 +192,13 @@ AC_ARG_ENABLE([debug],
[enable_debug=$enableval],
[enable_debug=no])
+# Turn warnings into errors
+AC_ARG_ENABLE([werror],
+ [AS_HELP_STRING([--enable-werror],
+ [Treat certain compiler warnings as errors (default is no)])],
+ [enable_werror=$enableval],
+ [enable_werror=no])
+
AC_LANG_PUSH([C++])
AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""])
@@ -199,10 +213,19 @@ if test "x$enable_debug" = xyes; then
fi
fi
+ERROR_CXXFLAGS=
+if test "x$enable_werror" = "xyes"; then
+ if test "x$CXXFLAG_WERROR" = "x"; then
+ AC_MSG_ERROR("enable-werror set but -Werror is not usable")
+ fi
+ AX_CHECK_COMPILE_FLAG([-Werror=vla],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=vla"],,[[$CXXFLAG_WERROR]])
+fi
+
if test "x$CXXFLAGS_overridden" = "xno"; then
AX_CHECK_COMPILE_FLAG([-Wall],[CXXFLAGS="$CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wextra],[CXXFLAGS="$CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wformat],[CXXFLAGS="$CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]])
+ AX_CHECK_COMPILE_FLAG([-Wvla],[CXXFLAGS="$CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wformat-security],[CXXFLAGS="$CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]])
## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all
@@ -312,6 +335,7 @@ case $host in
fi
fi
+ AC_PATH_PROGS([RSVG_CONVERT], [rsvg-convert rsvg],rsvg-convert)
AC_CHECK_PROG([BREW],brew, brew)
if test x$BREW = xbrew; then
dnl These Homebrew packages may be keg-only, meaning that they won't be found
@@ -366,8 +390,15 @@ case $host in
TARGET_OS=linux
LEVELDB_TARGET_FLAGS="-DOS_LINUX"
;;
+ *freebsd*)
+ LEVELDB_TARGET_FLAGS="-DOS_FREEBSD"
+ ;;
+ *openbsd*)
+ LEVELDB_TARGET_FLAGS="-DOS_OPENBSD"
+ ;;
*)
OTHER_OS=`echo ${host_os} | awk '{print toupper($0)}'`
+ AC_MSG_WARN([Guessing LevelDB OS as OS_${OTHER_OS}, please check whether this is correct, if not add an entry to configure.ac.])
LEVELDB_TARGET_FLAGS="-DOS_${OTHER_OS}"
;;
esac
@@ -382,21 +413,8 @@ if test x$use_pkgconfig = xyes; then
])
fi
-if test x$use_comparison_tool != xno; then
- AC_SUBST(JAVA_COMPARISON_TOOL, $use_comparison_tool)
-fi
-
-if test x$use_comparison_tool_reorg_tests != xno; then
- if test x$use_comparison_tool = x; then
- AC_MSG_ERROR("comparison tool reorg tests but comparison tool was not specified")
- fi
- AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 1)
-else
- AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 0)
-fi
-
-if test x$use_extended_rpc_tests != xno; then
- AC_SUBST(EXTENDED_RPC_TESTS, -extended)
+if test x$use_extended_functional_tests != xno; then
+ AC_SUBST(EXTENDED_FUNCTIONAL_TESTS, --extended)
fi
if test x$use_lcov = xyes; then
@@ -406,19 +424,15 @@ if test x$use_lcov = xyes; then
if test x$GCOV = x; then
AC_MSG_ERROR("lcov testing requested but gcov not found")
fi
- if test x$JAVA = x; then
- AC_MSG_ERROR("lcov testing requested but java not found")
- fi
if test x$PYTHON = x; then
AC_MSG_ERROR("lcov testing requested but python not found")
fi
if test x$GENHTML = x; then
AC_MSG_ERROR("lcov testing requested but genhtml not found")
fi
- if test x$use_comparison_tool = x; then
- AC_MSG_ERROR("lcov testing requested but comparison tool was not specified")
- fi
LCOV="$LCOV --gcov-tool=$GCOV"
+ AX_CHECK_LINK_FLAG([[--coverage]], [LDFLAGS="$LDFLAGS --coverage"],
+ [AC_MSG_ERROR("lcov testing requested but --coverage linker flag does not work")])
AX_CHECK_COMPILE_FLAG([--coverage],[CXXFLAGS="$CXXFLAGS --coverage"],
[AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")])
fi
@@ -495,6 +509,7 @@ if test x$use_hardening != xno; then
AX_CHECK_LINK_FLAG([[-Wl,--dynamicbase]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--dynamicbase"])
AX_CHECK_LINK_FLAG([[-Wl,--nxcompat]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--nxcompat"])
+ AX_CHECK_LINK_FLAG([[-Wl,--high-entropy-va]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--high-entropy-va"])
AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"])
AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"])
@@ -516,11 +531,12 @@ if test x$TARGET_OS = xdarwin; then
fi
AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h])
-AC_SEARCH_LIBS([getaddrinfo_a], [anl], [AC_DEFINE(HAVE_GETADDRINFO_A, 1, [Define this symbol if you have getaddrinfo_a])])
-AC_SEARCH_LIBS([inet_pton], [nsl resolv], [AC_DEFINE(HAVE_INET_PTON, 1, [Define this symbol if you have inet_pton])])
AC_CHECK_DECLS([strnlen])
+# Check for daemon(3), unrelated to --with-daemon (although used by it)
+AC_CHECK_DECLS([daemon])
+
AC_CHECK_DECLS([le16toh, le32toh, le64toh, htole16, htole32, htole64, be16toh, be32toh, be64toh, htobe16, htobe32, htobe64],,,
[#if HAVE_ENDIAN_H
#include <endian.h>
@@ -533,6 +549,8 @@ AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64],,,
#include <byteswap.h>
#endif])
+AC_CHECK_DECLS([__builtin_clz, __builtin_clzl, __builtin_clzll])
+
dnl Check for MSG_NOSIGNAL
AC_MSG_CHECKING(for MSG_NOSIGNAL)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],
@@ -541,6 +559,30 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],
[ AC_MSG_RESULT(no)]
)
+dnl Check for MSG_DONTWAIT
+AC_MSG_CHECKING(for MSG_DONTWAIT)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],
+ [[ int f = MSG_DONTWAIT; ]])],
+ [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_DONTWAIT, 1,[Define this symbol if you have MSG_DONTWAIT]) ],
+ [ AC_MSG_RESULT(no)]
+)
+
+dnl Check for malloc_info (for memory statistics information in getmemoryinfo)
+AC_MSG_CHECKING(for getmemoryinfo)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],
+ [[ int f = malloc_info(0, NULL); ]])],
+ [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MALLOC_INFO, 1,[Define this symbol if you have malloc_info]) ],
+ [ AC_MSG_RESULT(no)]
+)
+
+dnl Check for mallopt(M_ARENA_MAX) (to set glibc arenas)
+AC_MSG_CHECKING(for mallopt M_ARENA_MAX)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],
+ [[ mallopt(M_ARENA_MAX, 1); ]])],
+ [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MALLOPT_ARENA_MAX, 1,[Define this symbol if you have mallopt with M_ARENA_MAX]) ],
+ [ AC_MSG_RESULT(no)]
+)
+
AC_MSG_CHECKING([for visibility attribute])
AC_LINK_IFELSE([AC_LANG_SOURCE([
int foo_def( void ) __attribute__((visibility("default")));
@@ -558,6 +600,33 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
]
)
+# Check for different ways of gathering OS randomness
+AC_MSG_CHECKING(for Linux getrandom syscall)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>
+ #include <sys/syscall.h>
+ #include <linux/random.h>]],
+ [[ syscall(SYS_getrandom, nullptr, 32, 0); ]])],
+ [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYS_GETRANDOM, 1,[Define this symbol if the Linux getrandom system call is available]) ],
+ [ AC_MSG_RESULT(no)]
+)
+
+AC_MSG_CHECKING(for getentropy)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>]],
+ [[ getentropy(nullptr, 32) ]])],
+ [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_GETENTROPY, 1,[Define this symbol if the BSD getentropy system call is available]) ],
+ [ AC_MSG_RESULT(no)]
+)
+
+AC_MSG_CHECKING(for sysctl KERN_ARND)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+ #include <sys/sysctl.h>]],
+ [[ static const int name[2] = {CTL_KERN, KERN_ARND};
+ sysctl(name, 2, nullptr, nullptr, nullptr, 0); ]])],
+ [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSCTL_ARND, 1,[Define this symbol if the BSD sysctl(KERN_ARND) is available]) ],
+ [ AC_MSG_RESULT(no)]
+)
+
+# Check for reduced exports
if test x$use_reduce_exports = xyes; then
AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"],
[AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduce-exports.])])
@@ -598,14 +667,21 @@ fi
if test x$use_boost = xyes; then
+dnl Minimum required Boost version
+define(MINIMUM_REQUIRED_BOOST, 1.47.0)
+
dnl Check for boost libs
-AX_BOOST_BASE
+AX_BOOST_BASE([MINIMUM_REQUIRED_BOOST])
AX_BOOST_SYSTEM
AX_BOOST_FILESYSTEM
AX_BOOST_PROGRAM_OPTIONS
AX_BOOST_THREAD
AX_BOOST_CHRONO
+dnl Boost 1.56 through 1.62 allow using std::atomic instead of its own atomic
+dnl counter implementations. In 1.63 and later the std::atomic approach is default.
+m4_pattern_allow(DBOOST_AC_USE_STD_ATOMIC) dnl otherwise it's treated like a macro
+BOOST_CPPFLAGS="-DBOOST_SP_USE_STD_ATOMIC -DBOOST_AC_USE_STD_ATOMIC $BOOST_CPPFLAGS"
if test x$use_reduce_exports = xyes; then
AC_MSG_CHECKING([for working boost reduced exports])
@@ -816,6 +892,15 @@ else
AC_DEFINE_UNQUOTED([ENABLE_ZMQ],[0],[Define to 1 to enable ZMQ functions])
fi
+ if test "x$use_zmq" = "xyes"; then
+ dnl Assume libzmq was built for static linking
+ case $host in
+ *mingw*)
+ ZMQ_CFLAGS="$ZMQ_CFLAGS -DZMQ_STATIC"
+ ;;
+ esac
+ fi
+
BITCOIN_QT_CHECK(AC_CHECK_LIB([protobuf] ,[main],[PROTOBUF_LIBS=-lprotobuf], BITCOIN_QT_FAIL(libprotobuf not found)))
if test x$use_qr != xno; then
BITCOIN_QT_CHECK([AC_CHECK_LIB([qrencode], [main],[QR_LIBS=-lqrencode], [have_qrencode=no])])
@@ -823,8 +908,21 @@ else
fi
fi
+save_CXXFLAGS="${CXXFLAGS}"
+CXXFLAGS="${CXXFLAGS} ${CRYPTO_CFLAGS} ${SSL_CFLAGS}"
+AC_CHECK_DECLS([EVP_MD_CTX_new],,,[AC_INCLUDES_DEFAULT
+#include <openssl/x509_vfy.h>
+])
+CXXFLAGS="${save_CXXFLAGS}"
+
dnl univalue check
+need_bundled_univalue=yes
+
+if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then
+ need_bundled_univalue=no
+else
+
if test x$system_univalue != xno ; then
found_univalue=no
if test x$use_pkgconfig = xyes; then
@@ -846,6 +944,7 @@ if test x$system_univalue != xno ; then
if test x$found_univalue = xyes ; then
system_univalue=yes
+ need_bundled_univalue=no
elif test x$system_univalue = xyes ; then
AC_MSG_ERROR([univalue not found])
else
@@ -853,22 +952,17 @@ if test x$system_univalue != xno ; then
fi
fi
-if test x$system_univalue = xno ; then
+if test x$need_bundled_univalue = xyes ; then
UNIVALUE_CFLAGS='-I$(srcdir)/univalue/include'
UNIVALUE_LIBS='univalue/libunivalue.la'
fi
-AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$system_univalue = xno])
+
+fi
+
+AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$need_bundled_univalue = xyes])
AC_SUBST(UNIVALUE_CFLAGS)
AC_SUBST(UNIVALUE_LIBS)
-CXXFLAGS_TEMP="$CXXFLAGS"
-LIBS_TEMP="$LIBS"
-CXXFLAGS="$CXXFLAGS $SSL_CFLAGS $CRYPTO_CFLAGS"
-LIBS="$LIBS $SSL_LIBS $CRYPTO_LIBS"
-AC_CHECK_HEADER([openssl/ec.h],, AC_MSG_ERROR(OpenSSL ec header missing),)
-CXXFLAGS="$CXXFLAGS_TEMP"
-LIBS="$LIBS_TEMP"
-
BITCOIN_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path)
AC_MSG_CHECKING([whether to build bitcoind])
@@ -1003,8 +1097,8 @@ else
AC_MSG_RESULT([no])
fi
-if test x$build_bitcoin_utils$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_tests = xnonononono; then
- AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui or --enable-tests])
+if test x$build_bitcoin_utils$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnononononono; then
+ AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-bench or --enable-tests])
fi
AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin])
@@ -1017,8 +1111,6 @@ AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes])
AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes])
AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes])
AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes])
-AM_CONDITIONAL([USE_COMPARISON_TOOL],[test x$use_comparison_tool != xno])
-AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reorg_test != xno])
AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes])
AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes])
@@ -1047,6 +1139,7 @@ AC_SUBST(BITCOIN_CLI_NAME)
AC_SUBST(BITCOIN_TX_NAME)
AC_SUBST(RELDFLAGS)
+AC_SUBST(ERROR_CXXFLAGS)
AC_SUBST(HARDENED_CXXFLAGS)
AC_SUBST(HARDENED_CPPFLAGS)
AC_SUBST(HARDENED_LDFLAGS)
@@ -1067,11 +1160,13 @@ AC_SUBST(EVENT_PTHREADS_LIBS)
AC_SUBST(ZMQ_LIBS)
AC_SUBST(PROTOBUF_LIBS)
AC_SUBST(QR_LIBS)
-AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py])
-AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh])
-AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py])
+AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist test/functional/config.ini])
+AC_CONFIG_FILES([test/util/buildenv.py],[chmod +x test/util/buildenv.py])
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
-AC_CONFIG_LINKS([qa/pull-tester/rpc-tests.py:qa/pull-tester/rpc-tests.py])
+AC_CONFIG_FILES([doc/Doxyfile])
+AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py])
+AC_CONFIG_LINKS([test/util/bitcoin-util-test.py:test/util/bitcoin-util-test.py])
+AC_CONFIG_LINKS([test/util/bctest.py:test/util/bctest.py])
dnl boost's m4 checks do something really nasty: they export these vars. As a
dnl result, they leak into secp256k1's configure and crazy things happen.
@@ -1096,7 +1191,7 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR"
unset PKG_CONFIG_LIBDIR
PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP"
-if test x$system_univalue = xno; then
+if test x$need_bundled_univalue = xyes; then
AC_CONFIG_SUBDIRS([src/univalue])
fi
@@ -1119,7 +1214,33 @@ esac
dnl Replace the BUILDDIR path with the correct Windows path if compiling on Native Windows
case ${OS} in
*Windows*)
- sed 's/BUILDDIR="\/\([[a-z]]\)/BUILDDIR="\1:/' qa/pull-tester/tests_config.py > qa/pull-tester/tests_config-2.py
- mv qa/pull-tester/tests_config-2.py qa/pull-tester/tests_config.py
+ sed 's/BUILDDIR="\/\([[a-z]]\)/BUILDDIR="\1:/' test/functional/config.ini > test/functional/config-2.ini
+ mv test/functional/config-2.ini test/functional/config.ini
;;
esac
+
+echo
+echo "Options used to compile and link:"
+echo " with wallet = $enable_wallet"
+echo " with gui / qt = $bitcoin_enable_qt"
+if test x$bitcoin_enable_qt != xno; then
+ echo " qt version = $bitcoin_qt_got_major_vers"
+ echo " with qr = $use_qr"
+fi
+echo " with zmq = $use_zmq"
+echo " with test = $use_tests"
+echo " with bench = $use_bench"
+echo " with upnp = $use_upnp"
+echo " debug enabled = $enable_debug"
+echo " werror = $enable_werror"
+echo
+echo " target os = $TARGET_OS"
+echo " build os = $BUILD_OS"
+echo
+echo " CC = $CC"
+echo " CFLAGS = $CFLAGS"
+echo " CPPFLAGS = $CPPFLAGS"
+echo " CXX = $CXX"
+echo " CXXFLAGS = $CXXFLAGS"
+echo " LDFLAGS = $LDFLAGS"
+echo
diff --git a/contrib/README.md b/contrib/README.md
index a23b197cc6..6f750106e4 100644
--- a/contrib/README.md
+++ b/contrib/README.md
@@ -1,17 +1,9 @@
-Wallet Tools
----------------------
-
-### [SpendFrom](/contrib/spendfrom) ###
-
-Use the raw transactions API to send coins received on a particular
-address (or addresses).
-
Repository Tools
---------------------
### [Developer tools](/contrib/devtools) ###
Specific tools for developers working on this repository.
-Contains the script `github-merge.py` for merging github pull requests securely and signing them using GPG.
+Contains the script `github-merge.py` for merging GitHub pull requests securely and signing them using GPG.
### [Verify-Commits](/contrib/verify-commits) ###
Tool to verify that every merge commit was signed by a developer using the above `github-merge.py` script.
@@ -45,6 +37,9 @@ Scripts and notes for Mac builds.
### [RPM](/contrib/rpm) ###
RPM spec file for building bitcoin-core on RPM based distributions
+### [Gitian-build](/contrib/gitian-build.sh) ###
+Script for running full Gitian builds.
+
Test and Verify Tools
---------------------
diff --git a/contrib/debian/bitcoin-qt.desktop b/contrib/debian/bitcoin-qt.desktop
index 61e1aca6ad..593d7584ab 100644
--- a/contrib/debian/bitcoin-qt.desktop
+++ b/contrib/debian/bitcoin-qt.desktop
@@ -1,7 +1,8 @@
[Desktop Entry]
Encoding=UTF-8
-Name=Bitcoin
-Comment=Bitcoin P2P Cryptocurrency
+Name=Bitcoin Core
+Comment=Connect to the Bitcoin P2P Network
+Comment[de]=Verbinde mit dem Bitcoin peer-to-peer Netzwerk
Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair
Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi
Exec=bitcoin-qt %u
diff --git a/contrib/debian/bitcoin-qt.manpages b/contrib/debian/bitcoin-qt.manpages
new file mode 100644
index 0000000000..9a3cc31c09
--- /dev/null
+++ b/contrib/debian/bitcoin-qt.manpages
@@ -0,0 +1 @@
+doc/man/bitcoin-qt.1
diff --git a/contrib/debian/bitcoin-tx.manpages b/contrib/debian/bitcoin-tx.manpages
new file mode 100644
index 0000000000..861d49d070
--- /dev/null
+++ b/contrib/debian/bitcoin-tx.manpages
@@ -0,0 +1 @@
+doc/man/bitcoin-tx.1
diff --git a/contrib/debian/bitcoind.manpages b/contrib/debian/bitcoind.manpages
index 6d3e683855..bab644ece1 100644
--- a/contrib/debian/bitcoind.manpages
+++ b/contrib/debian/bitcoind.manpages
@@ -1,3 +1,2 @@
-debian/manpages/bitcoind.1
-debian/manpages/bitcoin.conf.5
-debian/manpages/bitcoin-cli.1
+doc/man/bitcoind.1
+doc/man/bitcoin-cli.1
diff --git a/contrib/debian/changelog b/contrib/debian/changelog
index 110bfe03ef..33dab9b638 100644
--- a/contrib/debian/changelog
+++ b/contrib/debian/changelog
@@ -1,3 +1,122 @@
+bitcoin (0.14.1-trusty4) trusty; urgency=medium
+
+ * Re-enable UPnP support.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Fri, 05 May 2017 13:28:00 -0400
+
+bitcoin (0.14.1-trusty3) trusty; urgency=medium
+
+ * Build with qt5 if we are on a non-Ubuntu (ie non-Unity) distro.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 04 May 2017 17:13:00 -0400
+
+bitcoin (0.14.1-trusty2) trusty; urgency=medium
+
+ * Bump minimum boost version in deps.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 04 May 2017 17:12:00 -0400
+
+bitcoin (0.14.1-trusty1) trusty; urgency=medium
+
+ * New upstream release.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Sat, 22 Apr 2017 17:10:00 -0400
+
+bitcoin (0.14.0-trusty1) trusty; urgency=medium
+
+ * New upstream release.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Wed, 08 Mar 2017 10:30:00 -0500
+
+bitcoin (0.13.2-trusty1) trusty; urgency=medium
+
+ * New upstream release.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 05 Jan 2017 09:59:00 -0500
+
+bitcoin (0.13.1-trusty2) trusty; urgency=medium
+
+ * Revert to Qt4, due to https://github.com/bitcoin/bitcoin/issues/9038
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Mon, 31 Oct 2016 11:16:00 -0400
+
+bitcoin (0.13.1-trusty1) trusty; urgency=medium
+
+ * New upstream release.
+ * Backport updated bitcoin-qt.desktop from upstream master
+ * Add zmq dependency
+ * Switch to Qt5 (breaks precise, but that was already broken by C++11)
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Thu, 27 Oct 2016 17:32:00 -0400
+
+bitcoin (0.13.0-trusty1) trusty; urgency=medium
+
+ * New upstream release.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Sun, 04 Sep 2016 22:09:00 -0400
+
+bitcoin (0.12.1-trusty1) trusty; urgency=medium
+
+ * New upstream release.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Mon, 18 Apr 2016 14:26:00 -0700
+
+bitcoin (0.12.0-trusty6) trusty; urgency=medium
+
+ * Fix program-options dep.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Fri, 25 Mar 2016 21:41:00 -0700
+
+bitcoin (0.12.0-trusty5) trusty; urgency=medium
+
+ * Test explicit --with-gui
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 23:25:00 -0800
+
+bitcoin (0.12.0-trusty4) trusty; urgency=medium
+
+ * Fix libevent-dev dep.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 23:25:00 -0800
+
+bitcoin (0.12.0-trusty3) trusty; urgency=medium
+
+ * Fix precise boost dep.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 19:55:00 -0800
+
+bitcoin (0.12.0-trusty2) trusty; urgency=medium
+
+ * Fix libevent dep.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 19:53:00 -0800
+
+bitcoin (0.12.0-trusty1) trusty; urgency=medium
+
+ * New upstream release
+ * Various updates to contrib/debian were merged, a few were not
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Tue, 23 Feb 2015 19:29:00 -0800
+
+bitcoin (0.11.2-trusty1) trusty; urgency=low
+
+ * New upstream release.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Fri, 13 Nov 2015 18:39:00 -0800
+
+bitcoin (0.11.1-trusty2) trusty; urgency=low
+
+ * Remove minupnpc builddep.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Wed, 14 Oct 2015 23:06:00 -1000
+
+bitcoin (0.11.1-trusty1) trusty; urgency=high
+
+ * New upstream release.
+ * Disable all UPnP support.
+
+ -- Matt Corallo (BlueMatt) <matt@mattcorallo.com> Wed, 14 Oct 2015 13:57:00 -1000
+
bitcoin (0.11.0-precise1) precise; urgency=medium
* New upstream release.
@@ -179,7 +298,7 @@ bitcoin (0.5.3-natty0) natty; urgency=low
bitcoin (0.5.2-natty1) natty; urgency=low
* Remove mentions on anonymity in package descriptions and manpage.
- These should never have been there, bitcoin isn't anonymous without
+ These should never have been there, bitcoin isnt anonymous without
a ton of work that virtually no users will ever be willing and
capable of doing
@@ -220,7 +339,7 @@ bitcoin (0.5.0~rc1-natty1) natty; urgency=low
* Add test_bitcoin to build test
* Fix clean
- * Remove unnecessary build-dependancies
+ * Remove uneccessary build-dependancies
-- Matt Corallo <matt@bluematt.me> Wed, 26 Oct 2011 14:37:18 -0400
@@ -380,7 +499,7 @@ bitcoin (0.3.20.01~dfsg-1) unstable; urgency=low
bitcoin (0.3.19~dfsg-6) unstable; urgency=low
- * Fix override aggressive optimizations.
+ * Fix override agressive optimizations.
* Fix tighten build-dependencies to really fit backporting to Lenny:
+ Add fallback build-dependency on libdb4.6++-dev.
+ Tighten unversioned Boost build-dependencies to recent versions,
diff --git a/contrib/debian/control b/contrib/debian/control
index fce6bc0118..0d6ad25e24 100644
--- a/contrib/debian/control
+++ b/contrib/debian/control
@@ -1,27 +1,30 @@
Source: bitcoin
Section: utils
Priority: optional
-Maintainer: Jonas Smedegaard <dr@jones.dk>
-Uploaders: Micah Anderson <micah@debian.org>
+Maintainer: Matt Corallo <matt@mattcorallo.com>
+Uploaders: Matt Corallo <matt@mattcorallo.com>
Build-Depends: debhelper,
devscripts,
automake,
libtool,
bash-completion,
- libboost-system-dev (>> 1.35) | libboost-system1.35-dev,
libdb4.8++-dev,
libssl-dev,
pkg-config,
- libminiupnpc8-dev | libminiupnpc-dev (>> 1.6),
- libboost-filesystem-dev (>> 1.35) | libboost-filesystem1.35-dev,
- libboost-program-options-dev (>> 1.35) | libboost-program-options1.35-dev,
- libboost-thread-dev (>> 1.35) | libboost-thread1.35-dev,
- libboost-test-dev (>> 1.35) | libboost-test1.35-dev,
- qt4-qmake,
- libqt4-dev,
+ libevent-dev,
+ libboost-system1.48-dev | libboost-system-dev (>> 1.47),
+ libboost-filesystem1.48-dev | libboost-filesystem-dev (>> 1.47),
+ libboost-program-options1.48-dev | libboost-program-options-dev (>> 1.47),
+ libboost-thread1.48-dev | libboost-thread-dev (>> 1.47),
+ libboost-test1.48-dev | libboost-test-dev (>> 1.47),
+ libboost-chrono1.48-dev | libboost-chrono-dev (>> 1.47),
+ libminiupnpc8-dev | libminiupnpc-dev,
+ qt4-qmake, libqt4-dev,
+ qttools5-dev-tools, qttools5-dev,
libqrencode-dev,
libprotobuf-dev, protobuf-compiler,
- python
+ python,
+ libzmq3-dev
Standards-Version: 3.9.2
Homepage: https://bitcoincore.org/
Vcs-Git: git://github.com/bitcoin/bitcoin.git
@@ -31,11 +34,11 @@ Package: bitcoind
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: peer-to-peer network based digital currency - daemon
- Bitcoin is an experimental new digital currency that enables instant
- payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer
- technology to operate with no central authority: managing transactions
- and issuing money are carried out collectively by the network. Bitcoin Core
- is the name of the open source software which enables the use of this currency.
+ Bitcoin is a free open source peer-to-peer electronic cash system that
+ is completely decentralized, without the need for a central server or
+ trusted parties. Users hold the crypto keys to their own money and
+ transact directly with each other, with the help of a P2P network to
+ check for double-spending.
.
This package provides the daemon, bitcoind, and the CLI tool
bitcoin-cli to interact with the daemon.
@@ -44,11 +47,11 @@ Package: bitcoin-qt
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: peer-to-peer network based digital currency - Qt GUI
- Bitcoin is an experimental new digital currency that enables instant
- payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer
- technology to operate with no central authority: managing transactions
- and issuing money are carried out collectively by the network. Bitcoin Core
- is the name of the open source software which enables the use of this currency.
+ Bitcoin is a free open source peer-to-peer electronic cash system that
+ is completely decentralized, without the need for a central server or
+ trusted parties. Users hold the crypto keys to their own money and
+ transact directly with each other, with the help of a P2P network to
+ check for double-spending.
.
This package provides Bitcoin-Qt, a GUI for Bitcoin based on Qt.
@@ -56,11 +59,11 @@ Package: bitcoin-tx
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: peer-to-peer digital currency - standalone transaction tool
- Bitcoin is an experimental new digital currency that enables instant
- payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer
- technology to operate with no central authority: managing transactions
- and issuing money are carried out collectively by the network. Bitcoin Core
- is the name of the open source software which enables the use of this currency.
+ Bitcoin is a free open source peer-to-peer electronic cash system that
+ is completely decentralized, without the need for a central server or
+ trusted parties. Users hold the crypto keys to their own money and
+ transact directly with each other, with the help of a P2P network to
+ check for double-spending.
.
This package provides bitcoin-tx, a command-line transaction creation
tool which can be used without a bitcoin daemon. Some means of
diff --git a/contrib/debian/copyright b/contrib/debian/copyright
index c039a7bae5..72d64ce62d 100644
--- a/contrib/debian/copyright
+++ b/contrib/debian/copyright
@@ -5,7 +5,7 @@ Upstream-Contact: Satoshi Nakamoto <satoshin@gmx.com>
Source: https://github.com/bitcoin/bitcoin
Files: *
-Copyright: 2009-2016, Bitcoin Core Developers
+Copyright: 2009-2017, Bitcoin Core Developers
License: Expat
Comment: The Bitcoin Core Developers encompasses the current developers listed on bitcoin.org,
as well as the numerous contributors to the project.
@@ -15,10 +15,6 @@ Copyright: 2010-2011, Jonas Smedegaard <dr@jones.dk>
2011, Matt Corallo <matt@bluematt.me>
License: GPL-2+
-Files: debian/manpages/*
-Copyright: Micah Anderson <micah@debian.org>
-License: GPL-3+
-
Files: src/qt/res/icons/add.png
src/qt/res/icons/address-book.png
src/qt/res/icons/chevron.png
@@ -51,7 +47,10 @@ Comment: Site: https://github.com/stephenhutchings/typicons.font
Files: src/qt/res/icons/connect*.png
src/qt/res/src/connect-*.svg
+ src/qt/res/icons/network_disabled.png
+ src/qt/res/src/network_disabled.svg
Copyright: Marco Falke
+ Luke Dashjr
License: Expat
Comment: Inspired by Stephan Hutchings Typicons
@@ -59,6 +58,10 @@ Files: src/qt/res/icons/tx_mined.png
src/qt/res/src/mine.svg
src/qt/res/icons/fontbigger.png
src/qt/res/icons/fontsmaller.png
+ src/qt/res/icons/hd_disabled.png
+ src/qt/res/src/hd_disabled.svg
+ src/qt/res/icons/hd_enabled.png
+ src/qt/res/src/hd_enabled.svg
Copyright: Jonas Schnelli
License: Expat
Comment:
diff --git a/contrib/debian/examples/bitcoin.conf b/contrib/debian/examples/bitcoin.conf
index 2831c07292..1029a51073 100644
--- a/contrib/debian/examples/bitcoin.conf
+++ b/contrib/debian/examples/bitcoin.conf
@@ -67,9 +67,30 @@
# This option can be specified multiple times (default: bind to all interfaces)
#rpcbind=<addr>
-# You must set rpcuser and rpcpassword to secure the JSON-RPC api
+# If no rpcpassword is set, rpc cookie auth is sought. The default `-rpccookiefile` name
+# is .cookie and found in the `-datadir` being used for bitcoind. This option is typically used
+# when the server and client are run as the same user.
+#
+# If not, you must set rpcuser and rpcpassword to secure the JSON-RPC api. The first
+# method(DEPRECATED) is to set this pair for the server and client:
#rpcuser=Ulysseys
#rpcpassword=YourSuperGreatPasswordNumber_DO_NOT_USE_THIS_OR_YOU_WILL_GET_ROBBED_385593
+#
+# The second method `rpcauth` can be added to server startup argument. It is set at intialization time
+# using the output from the script in share/rpcuser/rpcuser.py after providing a username:
+#
+# ./share/rpcuser/rpcuser.py alice
+# String to be appended to bitcoin.conf:
+# rpcauth=alice:f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae
+# Your password:
+# DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E=
+#
+# On client-side, you add the normal user/password pair to send commands:
+#rpcuser=alice
+#rpcpassword=DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E=
+#
+# You can even add multiple entries of these to the server conf file, and client can use any of them:
+# rpcauth=bob:b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99
# How many seconds bitcoin will wait for a complete RPC HTTP request.
# after the HTTP connection is established.
@@ -95,12 +116,7 @@
# running on another host using this option:
#rpcconnect=127.0.0.1
-# Transaction Fee Changes in 0.10.0
-
-# Send transactions as zero-fee transactions if possible (default: 0)
-#sendfreetransactions=0
-
-# Create transactions that have enough fees (or priority) so they are likely to begin confirmation within n blocks (default: 1).
+# Create transactions that have enough fees so they are likely to begin confirmation within n blocks (default: 6).
# This setting is over-ridden by the -paytxfee option.
#txconfirmtarget=n
@@ -115,6 +131,13 @@
# be validated sooner.
#paytxfee=0.00
+# Enable pruning to reduce storage requirements by deleting old blocks.
+# This mode is incompatible with -txindex and -rescan.
+# 0 = default (no pruning).
+# 1 = allows manual pruning via RPC.
+# >=550 = target to stay under in MiB.
+#prune=550
+
# User interface options
# Start Bitcoin minimized
diff --git a/contrib/debian/manpages/bitcoin-cli.1 b/contrib/debian/manpages/bitcoin-cli.1
deleted file mode 100644
index 16c338dd3e..0000000000
--- a/contrib/debian/manpages/bitcoin-cli.1
+++ /dev/null
@@ -1,21 +0,0 @@
-.TH BITCOIN-CLI "1" "February 2016" "bitcoin-cli 0.12"
-.SH NAME
-bitcoin-cli \- a remote procedure call client for Bitcoin Core.
-.SH SYNOPSIS
-bitcoin-cli [options] <command> [params] \- Send command to Bitcoin Core.
-.TP
-bitcoin-cli [options] help \- Asks Bitcoin Core for a list of supported commands.
-.SH DESCRIPTION
-This manual page documents the bitcoin-cli program. bitcoin-cli is an RPC client used to send commands to Bitcoin Core.
-
-.SH OPTIONS
-.TP
-\fB\-?\fR
-Show possible options.
-
-.SH "SEE ALSO"
-\fBbitcoind\fP, \fBbitcoin.conf\fP
-.SH AUTHOR
-This manual page was written by Ciemon Dunville <ciemon@gmail.com>. Permission is granted to copy, distribute and/or modify this document under the terms of the MIT License.
-
-The complete text of the MIT License can be found on the web at \fIhttp://opensource.org/licenses/MIT\fP.
diff --git a/contrib/debian/manpages/bitcoin-qt.1 b/contrib/debian/manpages/bitcoin-qt.1
deleted file mode 100644
index 685a282080..0000000000
--- a/contrib/debian/manpages/bitcoin-qt.1
+++ /dev/null
@@ -1,13 +0,0 @@
-.TH BITCOIN-QT "1" "February 2016" "bitcoin-qt 0.12"
-.SH NAME
-bitcoin-qt \- peer-to-peer network based digital currency
-.SH DESCRIPTION
-.SS "Usage:"
-.IP
-bitcoin\-qt [command\-line options]
-.SH OPTIONS
-.TP
-\-?
-List options.
-.SH "SEE ALSO"
-bitcoind(1)
diff --git a/contrib/debian/manpages/bitcoin.conf.5 b/contrib/debian/manpages/bitcoin.conf.5
deleted file mode 100644
index 839dc26c1a..0000000000
--- a/contrib/debian/manpages/bitcoin.conf.5
+++ /dev/null
@@ -1,19 +0,0 @@
-.TH BITCOIN.CONF "5" "February 2016" "bitcoin.conf 0.12"
-.SH NAME
-bitcoin.conf \- bitcoin configuration file
-.SH SYNOPSIS
-All command-line options (except for '\-conf') may be specified in a configuration file, and all configuration file options may also be specified on the command line. Command-line options override values set in the configuration file.
-.TP
-The configuration file is a list of 'setting=value' pairs, one per line, with optional comments starting with the '#' character. Please refer to bitcoind(1) for a up to date list of valid options.
-.TP
-The configuration file is not automatically created; you can create it using your favorite plain-text editor. By default, bitcoind(1) will look for a file named bitcoin.conf(5) in the bitcoin data directory, but both the data directory and the configuration file path may be changed using the '\-datadir' and '\-conf' command-line arguments.
-.SH LOCATION
-bitcoin.conf should be located in $HOME/.bitcoin
-
-.SH "SEE ALSO"
-bitcoind(1)
-.SH AUTHOR
-This manual page was written by Micah Anderson <micah@debian.org> for the Debian system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation.
-
-On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
-
diff --git a/contrib/debian/manpages/bitcoind.1 b/contrib/debian/manpages/bitcoind.1
deleted file mode 100644
index 5c3e52f441..0000000000
--- a/contrib/debian/manpages/bitcoind.1
+++ /dev/null
@@ -1,30 +0,0 @@
-.TH BITCOIND "1" "February 2016" "bitcoind 0.12"
-.SH NAME
-bitcoind \- peer-to-peer network based digital currency
-.SH SYNOPSIS
-bitcoin [options] <command> [params]
-.TP
-bitcoin [options] help <command> \- Get help for a command
-.SH DESCRIPTION
-This manual page documents the bitcoind program. Bitcoin is an experimental new digital currency that enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate with no central authority: managing transactions and issuing money are carried out collectively by the network. Bitcoin Core is the name of open source software which enables the use of this currency.
-
-.SH OPTIONS
-.TP
-\-?
-List of possible options.
-.SH COMMANDS
-.TP
-\fBhelp\fR
-List commands.
-
-.TP
-\fBhelp 'command'\fR
-Get help for a command.
-
-.SH "SEE ALSO"
-bitcoin.conf(5)
-.SH AUTHOR
-This manual page was written by Micah Anderson <micah@debian.org> for the Debian system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation.
-
-On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
-
diff --git a/contrib/debian/rules b/contrib/debian/rules
index 52b357cf01..6885e38521 100755
--- a/contrib/debian/rules
+++ b/contrib/debian/rules
@@ -5,9 +5,6 @@
#build/bitcoind::
# $(if $(filter nocheck,$(DEB_BUILD_OPTIONS)),,src/test_bitcoin)
-DEB_INSTALL_EXAMPLES_bitcoind += debian/examples/*
-DEB_INSTALL_MANPAGES_bitcoind += debian/manpages/*
-
%:
dh --with bash-completion $@
@@ -15,10 +12,12 @@ override_dh_auto_clean:
if [ -f Makefile ]; then $(MAKE) distclean; fi
rm -rf Makefile.in aclocal.m4 configure src/Makefile.in src/bitcoin-config.h.in src/build-aux src/qt/Makefile.in src/qt/test/Makefile.in src/test/Makefile.in
+QT=$(shell dpkg-vendor --derives-from Ubuntu && echo qt4 || echo qt5)
+
# Yea, autogen should be run on the source archive, but I like doing git archive
override_dh_auto_configure:
./autogen.sh
- ./configure
+ ./configure --with-gui=$(QT)
override_dh_auto_test:
make check
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
index bb8b9246b8..67c5e15a15 100644
--- a/contrib/devtools/README.md
+++ b/contrib/devtools/README.md
@@ -8,11 +8,6 @@ check-doc.py
Check if all command line args are documented. The return value indicates the
number of undocumented args.
-clang-format.py
-===============
-
-A script to format cpp source code according to [.clang-format](../../src/.clang-format). This should only be applied to new files or files which are currently not actively developed on. Also, git subtrees are not subject to formatting.
-
clang-format-diff.py
===================
@@ -25,20 +20,70 @@ the script should be called from the git root folder as follows.
git diff -U0 HEAD~1.. | ./contrib/devtools/clang-format-diff.py -p1 -i -v
```
-fix-copyright-headers.py
-========================
+copyright\_header.py
+====================
-Every year newly updated files need to have its copyright headers updated to reflect the current year.
-If you run this script from the root folder it will automatically update the year on the copyright header for all
-source files if these have a git commit from the current year.
+Provides utilities for managing copyright headers of `The Bitcoin Core
+developers` in repository source files. It has three subcommands:
-For example a file changed in 2015 (with 2015 being the current year):
+```
+$ ./copyright_header.py report <base_directory> [verbose]
+$ ./copyright_header.py update <base_directory>
+$ ./copyright_header.py insert <file>
+```
+Running these subcommands without arguments displays a usage string.
-```// Copyright (c) 2009-2013 The Bitcoin Core developers```
+copyright\_header.py report \<base\_directory\> [verbose]
+---------------------------------------------------------
-would be changed to:
+Produces a report of all copyright header notices found inside the source files
+of a repository. Useful to quickly visualize the state of the headers.
+Specifying `verbose` will list the full filenames of files of each category.
+
+copyright\_header.py update \<base\_directory\> [verbose]
+---------------------------------------------------------
+Updates all the copyright headers of `The Bitcoin Core developers` which were
+changed in a year more recent than is listed. For example:
+```
+// Copyright (c) <firstYear>-<lastYear> The Bitcoin Core developers
+```
+will be updated to:
+```
+// Copyright (c) <firstYear>-<lastModifiedYear> The Bitcoin Core developers
+```
+where `<lastModifiedYear>` is obtained from the `git log` history.
+
+This subcommand also handles copyright headers that have only a single year. In
+those cases:
+```
+// Copyright (c) <year> The Bitcoin Core developers
+```
+will be updated to:
+```
+// Copyright (c) <year>-<lastModifiedYear> The Bitcoin Core developers
+```
+where the update is appropriate.
+
+copyright\_header.py insert \<file\>
+------------------------------------
+Inserts a copyright header for `The Bitcoin Core developers` at the top of the
+file in either Python or C++ style as determined by the file extension. If the
+file is a Python file and it has `#!` starting the first line, the header is
+inserted in the line below it.
+
+The copyright dates will be set to be `<year_introduced>-<current_year>` where
+`<year_introduced>` is according to the `git log` history. If
+`<year_introduced>` is equal to `<current_year>`, it will be set as a single
+year rather than two hyphenated years.
+
+If the file already has a copyright for `The Bitcoin Core developers`, the
+script will exit.
+
+gen-manpages.sh
+===============
-```// Copyright (c) 2009-2015 The Bitcoin Core developers```
+A small script to automatically create manpages in ../../doc/man by running the release binaries with the -help option.
+This requires help2man which can be found at: https://www.gnu.org/software/help2man/
git-subtree-check.sh
====================
@@ -51,8 +96,9 @@ maintained:
* for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master)
* for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork)
* for `src/univalue`: https://github.com/bitcoin-core/univalue.git (branch master)
+* for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master)
-Usage: `git-subtree-check.sh DIR COMMIT`
+Usage: `git-subtree-check.sh DIR (COMMIT)`
`COMMIT` may be omitted, in which case `HEAD` is used.
@@ -79,7 +125,7 @@ check or whatever).
This means that there are no potential race conditions (where a
pullreq gets updated while you're reviewing it, but before you click
-merge), and when using GPG signatures, that even a compromised github
+merge), and when using GPG signatures, that even a compromised GitHub
couldn't mess with the sources.
Setup
diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py
index 9ea0131ac3..445175ec2b 100755
--- a/contrib/devtools/check-doc.py
+++ b/contrib/devtools/check-doc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Copyright (c) 2015 The Bitcoin Core developers
+# Copyright (c) 2015-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.
@@ -21,7 +21,7 @@ CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' %s" % (CMD_RO
REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"')
REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")')
# list unsupported, deprecated and duplicate args as they need no documentation
-SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize'])
+SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-sendfreetransactions'])
def main():
used = check_output(CMD_GREP_ARGS, shell=True)
diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py
index 13d2573b9f..7ea49b65e1 100755
--- a/contrib/devtools/clang-format-diff.py
+++ b/contrib/devtools/clang-format-diff.py
@@ -128,7 +128,7 @@ def main():
line_count = int(match.group(3))
if line_count == 0:
continue
- end_line = start_line + line_count - 1;
+ end_line = start_line + line_count - 1
lines_by_file.setdefault(filename, []).extend(
['-lines', str(start_line) + ':' + str(end_line)])
@@ -147,7 +147,7 @@ def main():
stderr=None, stdin=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
- sys.exit(p.returncode);
+ sys.exit(p.returncode)
if not args.i:
with open(filename) as f:
diff --git a/contrib/devtools/clang-format.py b/contrib/devtools/clang-format.py
deleted file mode 100755
index cee99047ac..0000000000
--- a/contrib/devtools/clang-format.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python
-'''
-Wrapper script for clang-format
-
-Copyright (c) 2015 MarcoFalke
-Copyright (c) 2015 The Bitcoin Core developers
-Distributed under the MIT software license, see the accompanying
-file COPYING or http://www.opensource.org/licenses/mit-license.php.
-'''
-
-import os
-import sys
-import subprocess
-
-tested_versions = ['3.6.0', '3.6.1', '3.6.2'] # A set of versions known to produce the same output
-accepted_file_extensions = ('.h', '.cpp') # Files to format
-
-def check_clang_format_version(clang_format_exe):
- try:
- output = subprocess.check_output([clang_format_exe, '-version'])
- for ver in tested_versions:
- if ver in output:
- print "Detected clang-format version " + ver
- return
- raise RuntimeError("Untested version: " + output)
- except Exception as e:
- print 'Could not verify version of ' + clang_format_exe + '.'
- raise e
-
-def check_command_line_args(argv):
- required_args = ['{clang-format-exe}', '{files}']
- example_args = ['clang-format-3.x', 'src/main.cpp', 'src/wallet/*']
-
- if(len(argv) < len(required_args) + 1):
- for word in (['Usage:', argv[0]] + required_args):
- print word,
- print ''
- for word in (['E.g:', argv[0]] + example_args):
- print word,
- print ''
- sys.exit(1)
-
-def run_clang_format(clang_format_exe, files):
- for target in files:
- if os.path.isdir(target):
- for path, dirs, files in os.walk(target):
- run_clang_format(clang_format_exe, (os.path.join(path, f) for f in files))
- elif target.endswith(accepted_file_extensions):
- print "Format " + target
- subprocess.check_call([clang_format_exe, '-i', '-style=file', target], stdout=open(os.devnull, 'wb'), stderr=subprocess.STDOUT)
- else:
- print "Skip " + target
-
-def main(argv):
- check_command_line_args(argv)
- clang_format_exe = argv[1]
- files = argv[2:]
- check_clang_format_version(clang_format_exe)
- run_clang_format(clang_format_exe, files)
-
-if __name__ == "__main__":
- main(sys.argv)
diff --git a/contrib/devtools/commit-script-check.sh b/contrib/devtools/commit-script-check.sh
new file mode 100755
index 0000000000..add4bb4883
--- /dev/null
+++ b/contrib/devtools/commit-script-check.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# 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 simple script checks for commits beginning with: scripted-diff:
+# If found, looks for a script between the lines -BEGIN VERIFY SCRIPT- and
+# -END VERIFY SCRIPT-. If no ending is found, it reads until the end of the
+# commit message.
+
+# The resulting script should exactly transform the previous commit into the current
+# one. Any remaining diff signals an error.
+
+if test "x$1" = "x"; then
+ echo "Usage: $0 <commit>..."
+ exit 1
+fi
+
+RET=0
+PREV_BRANCH=`git name-rev --name-only HEAD`
+PREV_HEAD=`git rev-parse HEAD`
+for i in `git rev-list --reverse $1`; do
+ git rev-list -n 1 --pretty="%s" $i | grep -q "^scripted-diff:" || continue
+ git checkout --quiet $i^ || exit
+ SCRIPT="`git rev-list --format=%b -n1 $i | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d'`"
+ if test "x$SCRIPT" = "x"; then
+ echo "Error: missing script for: $i"
+ echo "Failed"
+ RET=1
+ else
+ echo "Running script for: $i"
+ echo "$SCRIPT"
+ eval "$SCRIPT"
+ git --no-pager diff --exit-code $i && echo "OK" || (echo "Failed"; false) || RET=1
+ fi
+ git reset --quiet --hard HEAD
+done
+git checkout --quiet $PREV_BRANCH 2>/dev/null || git checkout --quiet $PREV_HEAD
+exit $RET
diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py
new file mode 100755
index 0000000000..6d801d3ac7
--- /dev/null
+++ b/contrib/devtools/copyright_header.py
@@ -0,0 +1,610 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+
+import re
+import fnmatch
+import sys
+import subprocess
+import datetime
+import os
+
+################################################################################
+# file filtering
+################################################################################
+
+EXCLUDE = [
+ # libsecp256k1:
+ 'src/secp256k1/include/secp256k1.h',
+ 'src/secp256k1/include/secp256k1_ecdh.h',
+ 'src/secp256k1/include/secp256k1_recovery.h',
+ 'src/secp256k1/include/secp256k1_schnorr.h',
+ 'src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c',
+ 'src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h',
+ 'src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c',
+ 'src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h',
+ # auto generated:
+ 'src/univalue/lib/univalue_escapes.h',
+ 'src/qt/bitcoinstrings.cpp',
+ 'src/chainparamsseeds.h',
+ # other external copyrights:
+ 'src/tinyformat.h',
+ 'src/leveldb/util/env_win.cc',
+ 'src/crypto/ctaes/bench.c',
+ 'test/functional/test_framework/bignum.py',
+ # python init:
+ '*__init__.py',
+]
+EXCLUDE_COMPILED = re.compile('|'.join([fnmatch.translate(m) for m in EXCLUDE]))
+
+INCLUDE = ['*.h', '*.cpp', '*.cc', '*.c', '*.py']
+INCLUDE_COMPILED = re.compile('|'.join([fnmatch.translate(m) for m in INCLUDE]))
+
+def applies_to_file(filename):
+ return ((EXCLUDE_COMPILED.match(filename) is None) and
+ (INCLUDE_COMPILED.match(filename) is not None))
+
+################################################################################
+# obtain list of files in repo according to INCLUDE and EXCLUDE
+################################################################################
+
+GIT_LS_CMD = 'git ls-files'
+
+def call_git_ls():
+ out = subprocess.check_output(GIT_LS_CMD.split(' '))
+ return [f for f in out.decode("utf-8").split('\n') if f != '']
+
+def get_filenames_to_examine():
+ filenames = call_git_ls()
+ return sorted([filename for filename in filenames if
+ applies_to_file(filename)])
+
+################################################################################
+# define and compile regexes for the patterns we are looking for
+################################################################################
+
+
+COPYRIGHT_WITH_C = 'Copyright \(c\)'
+COPYRIGHT_WITHOUT_C = 'Copyright'
+ANY_COPYRIGHT_STYLE = '(%s|%s)' % (COPYRIGHT_WITH_C, COPYRIGHT_WITHOUT_C)
+
+YEAR = "20[0-9][0-9]"
+YEAR_RANGE = '(%s)(-%s)?' % (YEAR, YEAR)
+YEAR_LIST = '(%s)(, %s)+' % (YEAR, YEAR)
+ANY_YEAR_STYLE = '(%s|%s)' % (YEAR_RANGE, YEAR_LIST)
+ANY_COPYRIGHT_STYLE_OR_YEAR_STYLE = ("%s %s" % (ANY_COPYRIGHT_STYLE,
+ ANY_YEAR_STYLE))
+
+ANY_COPYRIGHT_COMPILED = re.compile(ANY_COPYRIGHT_STYLE_OR_YEAR_STYLE)
+
+def compile_copyright_regex(copyright_style, year_style, name):
+ return re.compile('%s %s %s' % (copyright_style, year_style, name))
+
+EXPECTED_HOLDER_NAMES = [
+ "Satoshi Nakamoto\n",
+ "The Bitcoin Core developers\n",
+ "The Bitcoin Core developers \n",
+ "Bitcoin Core Developers\n",
+ "the Bitcoin Core developers\n",
+ "The Bitcoin developers\n",
+ "The LevelDB Authors\. All rights reserved\.\n",
+ "BitPay Inc\.\n",
+ "BitPay, Inc\.\n",
+ "University of Illinois at Urbana-Champaign\.\n",
+ "MarcoFalke\n",
+ "Pieter Wuille\n",
+ "Pieter Wuille +\*\n",
+ "Pieter Wuille, Gregory Maxwell +\*\n",
+ "Pieter Wuille, Andrew Poelstra +\*\n",
+ "Andrew Poelstra +\*\n",
+ "Wladimir J. van der Laan\n",
+ "Jeff Garzik\n",
+ "Diederik Huys, Pieter Wuille +\*\n",
+ "Thomas Daede, Cory Fields +\*\n",
+ "Jan-Klaas Kollhof\n",
+ "Sam Rushing\n",
+ "ArtForz -- public domain half-a-node\n",
+]
+
+DOMINANT_STYLE_COMPILED = {}
+YEAR_LIST_STYLE_COMPILED = {}
+WITHOUT_C_STYLE_COMPILED = {}
+
+for holder_name in EXPECTED_HOLDER_NAMES:
+ DOMINANT_STYLE_COMPILED[holder_name] = (
+ compile_copyright_regex(COPYRIGHT_WITH_C, YEAR_RANGE, holder_name))
+ YEAR_LIST_STYLE_COMPILED[holder_name] = (
+ compile_copyright_regex(COPYRIGHT_WITH_C, YEAR_LIST, holder_name))
+ WITHOUT_C_STYLE_COMPILED[holder_name] = (
+ compile_copyright_regex(COPYRIGHT_WITHOUT_C, ANY_YEAR_STYLE,
+ holder_name))
+
+################################################################################
+# search file contents for copyright message of particular category
+################################################################################
+
+def get_count_of_copyrights_of_any_style_any_holder(contents):
+ return len(ANY_COPYRIGHT_COMPILED.findall(contents))
+
+def file_has_dominant_style_copyright_for_holder(contents, holder_name):
+ match = DOMINANT_STYLE_COMPILED[holder_name].search(contents)
+ return match is not None
+
+def file_has_year_list_style_copyright_for_holder(contents, holder_name):
+ match = YEAR_LIST_STYLE_COMPILED[holder_name].search(contents)
+ return match is not None
+
+def file_has_without_c_style_copyright_for_holder(contents, holder_name):
+ match = WITHOUT_C_STYLE_COMPILED[holder_name].search(contents)
+ return match is not None
+
+################################################################################
+# get file info
+################################################################################
+
+def read_file(filename):
+ return open(os.path.abspath(filename), 'r').read()
+
+def gather_file_info(filename):
+ info = {}
+ info['filename'] = filename
+ c = read_file(filename)
+ info['contents'] = c
+
+ info['all_copyrights'] = get_count_of_copyrights_of_any_style_any_holder(c)
+
+ info['classified_copyrights'] = 0
+ info['dominant_style'] = {}
+ info['year_list_style'] = {}
+ info['without_c_style'] = {}
+ for holder_name in EXPECTED_HOLDER_NAMES:
+ has_dominant_style = (
+ file_has_dominant_style_copyright_for_holder(c, holder_name))
+ has_year_list_style = (
+ file_has_year_list_style_copyright_for_holder(c, holder_name))
+ has_without_c_style = (
+ file_has_without_c_style_copyright_for_holder(c, holder_name))
+ info['dominant_style'][holder_name] = has_dominant_style
+ info['year_list_style'][holder_name] = has_year_list_style
+ info['without_c_style'][holder_name] = has_without_c_style
+ if has_dominant_style or has_year_list_style or has_without_c_style:
+ info['classified_copyrights'] = info['classified_copyrights'] + 1
+ return info
+
+################################################################################
+# report execution
+################################################################################
+
+SEPARATOR = '-'.join(['' for _ in range(80)])
+
+def print_filenames(filenames, verbose):
+ if not verbose:
+ return
+ for filename in filenames:
+ print("\t%s" % filename)
+
+def print_report(file_infos, verbose):
+ print(SEPARATOR)
+ examined = [i['filename'] for i in file_infos]
+ print("%d files examined according to INCLUDE and EXCLUDE fnmatch rules" %
+ len(examined))
+ print_filenames(examined, verbose)
+
+ print(SEPARATOR)
+ print('')
+ zero_copyrights = [i['filename'] for i in file_infos if
+ i['all_copyrights'] == 0]
+ print("%4d with zero copyrights" % len(zero_copyrights))
+ print_filenames(zero_copyrights, verbose)
+ one_copyright = [i['filename'] for i in file_infos if
+ i['all_copyrights'] == 1]
+ print("%4d with one copyright" % len(one_copyright))
+ print_filenames(one_copyright, verbose)
+ two_copyrights = [i['filename'] for i in file_infos if
+ i['all_copyrights'] == 2]
+ print("%4d with two copyrights" % len(two_copyrights))
+ print_filenames(two_copyrights, verbose)
+ three_copyrights = [i['filename'] for i in file_infos if
+ i['all_copyrights'] == 3]
+ print("%4d with three copyrights" % len(three_copyrights))
+ print_filenames(three_copyrights, verbose)
+ four_or_more_copyrights = [i['filename'] for i in file_infos if
+ i['all_copyrights'] >= 4]
+ print("%4d with four or more copyrights" % len(four_or_more_copyrights))
+ print_filenames(four_or_more_copyrights, verbose)
+ print('')
+ print(SEPARATOR)
+ print('Copyrights with dominant style:\ne.g. "Copyright (c)" and '
+ '"<year>" or "<startYear>-<endYear>":\n')
+ for holder_name in EXPECTED_HOLDER_NAMES:
+ dominant_style = [i['filename'] for i in file_infos if
+ i['dominant_style'][holder_name]]
+ if len(dominant_style) > 0:
+ print("%4d with '%s'" % (len(dominant_style),
+ holder_name.replace('\n', '\\n')))
+ print_filenames(dominant_style, verbose)
+ print('')
+ print(SEPARATOR)
+ print('Copyrights with year list style:\ne.g. "Copyright (c)" and '
+ '"<year1>, <year2>, ...":\n')
+ for holder_name in EXPECTED_HOLDER_NAMES:
+ year_list_style = [i['filename'] for i in file_infos if
+ i['year_list_style'][holder_name]]
+ if len(year_list_style) > 0:
+ print("%4d with '%s'" % (len(year_list_style),
+ holder_name.replace('\n', '\\n')))
+ print_filenames(year_list_style, verbose)
+ print('')
+ print(SEPARATOR)
+ print('Copyrights with no "(c)" style:\ne.g. "Copyright" and "<year>" or '
+ '"<startYear>-<endYear>":\n')
+ for holder_name in EXPECTED_HOLDER_NAMES:
+ without_c_style = [i['filename'] for i in file_infos if
+ i['without_c_style'][holder_name]]
+ if len(without_c_style) > 0:
+ print("%4d with '%s'" % (len(without_c_style),
+ holder_name.replace('\n', '\\n')))
+ print_filenames(without_c_style, verbose)
+
+ print('')
+ print(SEPARATOR)
+
+ unclassified_copyrights = [i['filename'] for i in file_infos if
+ i['classified_copyrights'] < i['all_copyrights']]
+ print("%d with unexpected copyright holder names" %
+ len(unclassified_copyrights))
+ print_filenames(unclassified_copyrights, verbose)
+ print(SEPARATOR)
+
+def exec_report(base_directory, verbose):
+ original_cwd = os.getcwd()
+ os.chdir(base_directory)
+ filenames = get_filenames_to_examine()
+ file_infos = [gather_file_info(f) for f in filenames]
+ print_report(file_infos, verbose)
+ os.chdir(original_cwd)
+
+################################################################################
+# report cmd
+################################################################################
+
+REPORT_USAGE = """
+Produces a report of all copyright header notices found inside the source files
+of a repository.
+
+Usage:
+ $ ./copyright_header.py report <base_directory> [verbose]
+
+Arguments:
+ <base_directory> - The base directory of a bitcoin source code repository.
+ [verbose] - Includes a list of every file of each subcategory in the report.
+"""
+
+def report_cmd(argv):
+ if len(argv) == 2:
+ sys.exit(REPORT_USAGE)
+
+ base_directory = argv[2]
+ if not os.path.exists(base_directory):
+ sys.exit("*** bad <base_directory>: %s" % base_directory)
+
+ if len(argv) == 3:
+ verbose = False
+ elif argv[3] == 'verbose':
+ verbose = True
+ else:
+ sys.exit("*** unknown argument: %s" % argv[2])
+
+ exec_report(base_directory, verbose)
+
+################################################################################
+# query git for year of last change
+################################################################################
+
+GIT_LOG_CMD = "git log --pretty=format:%%ai %s"
+
+def call_git_log(filename):
+ out = subprocess.check_output((GIT_LOG_CMD % filename).split(' '))
+ return out.decode("utf-8").split('\n')
+
+def get_git_change_years(filename):
+ git_log_lines = call_git_log(filename)
+ if len(git_log_lines) == 0:
+ return [datetime.date.today().year]
+ # timestamp is in ISO 8601 format. e.g. "2016-09-05 14:25:32 -0600"
+ return [line.split(' ')[0].split('-')[0] for line in git_log_lines]
+
+def get_most_recent_git_change_year(filename):
+ return max(get_git_change_years(filename))
+
+################################################################################
+# read and write to file
+################################################################################
+
+def read_file_lines(filename):
+ f = open(os.path.abspath(filename), 'r')
+ file_lines = f.readlines()
+ f.close()
+ return file_lines
+
+def write_file_lines(filename, file_lines):
+ f = open(os.path.abspath(filename), 'w')
+ f.write(''.join(file_lines))
+ f.close()
+
+################################################################################
+# update header years execution
+################################################################################
+
+COPYRIGHT = 'Copyright \(c\)'
+YEAR = "20[0-9][0-9]"
+YEAR_RANGE = '(%s)(-%s)?' % (YEAR, YEAR)
+HOLDER = 'The Bitcoin Core developers'
+UPDATEABLE_LINE_COMPILED = re.compile(' '.join([COPYRIGHT, YEAR_RANGE, HOLDER]))
+
+def get_updatable_copyright_line(file_lines):
+ index = 0
+ for line in file_lines:
+ if UPDATEABLE_LINE_COMPILED.search(line) is not None:
+ return index, line
+ index = index + 1
+ return None, None
+
+def parse_year_range(year_range):
+ year_split = year_range.split('-')
+ start_year = year_split[0]
+ if len(year_split) == 1:
+ return start_year, start_year
+ return start_year, year_split[1]
+
+def year_range_to_str(start_year, end_year):
+ if start_year == end_year:
+ return start_year
+ return "%s-%s" % (start_year, end_year)
+
+def create_updated_copyright_line(line, last_git_change_year):
+ copyright_splitter = 'Copyright (c) '
+ copyright_split = line.split(copyright_splitter)
+ # Preserve characters on line that are ahead of the start of the copyright
+ # notice - they are part of the comment block and vary from file-to-file.
+ before_copyright = copyright_split[0]
+ after_copyright = copyright_split[1]
+
+ space_split = after_copyright.split(' ')
+ year_range = space_split[0]
+ start_year, end_year = parse_year_range(year_range)
+ if end_year == last_git_change_year:
+ return line
+ return (before_copyright + copyright_splitter +
+ year_range_to_str(start_year, last_git_change_year) + ' ' +
+ ' '.join(space_split[1:]))
+
+def update_updatable_copyright(filename):
+ file_lines = read_file_lines(filename)
+ index, line = get_updatable_copyright_line(file_lines)
+ if not line:
+ print_file_action_message(filename, "No updatable copyright.")
+ return
+ last_git_change_year = get_most_recent_git_change_year(filename)
+ new_line = create_updated_copyright_line(line, last_git_change_year)
+ if line == new_line:
+ print_file_action_message(filename, "Copyright up-to-date.")
+ return
+ file_lines[index] = new_line
+ write_file_lines(filename, file_lines)
+ print_file_action_message(filename,
+ "Copyright updated! -> %s" % last_git_change_year)
+
+def exec_update_header_year(base_directory):
+ original_cwd = os.getcwd()
+ os.chdir(base_directory)
+ for filename in get_filenames_to_examine():
+ update_updatable_copyright(filename)
+ os.chdir(original_cwd)
+
+################################################################################
+# update cmd
+################################################################################
+
+UPDATE_USAGE = """
+Updates all the copyright headers of "The Bitcoin Core developers" which were
+changed in a year more recent than is listed. For example:
+
+// Copyright (c) <firstYear>-<lastYear> The Bitcoin Core developers
+
+will be updated to:
+
+// Copyright (c) <firstYear>-<lastModifiedYear> The Bitcoin Core developers
+
+where <lastModifiedYear> is obtained from the 'git log' history.
+
+This subcommand also handles copyright headers that have only a single year. In those cases:
+
+// Copyright (c) <year> The Bitcoin Core developers
+
+will be updated to:
+
+// Copyright (c) <year>-<lastModifiedYear> The Bitcoin Core developers
+
+where the update is appropriate.
+
+Usage:
+ $ ./copyright_header.py update <base_directory>
+
+Arguments:
+ <base_directory> - The base directory of a bitcoin source code repository.
+"""
+
+def print_file_action_message(filename, action):
+ print("%-52s %s" % (filename, action))
+
+def update_cmd(argv):
+ if len(argv) != 3:
+ sys.exit(UPDATE_USAGE)
+
+ base_directory = argv[2]
+ if not os.path.exists(base_directory):
+ sys.exit("*** bad base_directory: %s" % base_directory)
+ exec_update_header_year(base_directory)
+
+################################################################################
+# inserted copyright header format
+################################################################################
+
+def get_header_lines(header, start_year, end_year):
+ lines = header.split('\n')[1:-1]
+ lines[0] = lines[0] % year_range_to_str(start_year, end_year)
+ return [line + '\n' for line in lines]
+
+CPP_HEADER = '''
+// Copyright (c) %s The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+'''
+
+def get_cpp_header_lines_to_insert(start_year, end_year):
+ return reversed(get_header_lines(CPP_HEADER, start_year, end_year))
+
+PYTHON_HEADER = '''
+# Copyright (c) %s The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+'''
+
+def get_python_header_lines_to_insert(start_year, end_year):
+ return reversed(get_header_lines(PYTHON_HEADER, start_year, end_year))
+
+################################################################################
+# query git for year of last change
+################################################################################
+
+def get_git_change_year_range(filename):
+ years = get_git_change_years(filename)
+ return min(years), max(years)
+
+################################################################################
+# check for existing core copyright
+################################################################################
+
+def file_already_has_core_copyright(file_lines):
+ index, _ = get_updatable_copyright_line(file_lines)
+ return index != None
+
+################################################################################
+# insert header execution
+################################################################################
+
+def file_has_hashbang(file_lines):
+ if len(file_lines) < 1:
+ return False
+ if len(file_lines[0]) <= 2:
+ return False
+ return file_lines[0][:2] == '#!'
+
+def insert_python_header(filename, file_lines, start_year, end_year):
+ if file_has_hashbang(file_lines):
+ insert_idx = 1
+ else:
+ insert_idx = 0
+ header_lines = get_python_header_lines_to_insert(start_year, end_year)
+ for line in header_lines:
+ file_lines.insert(insert_idx, line)
+ write_file_lines(filename, file_lines)
+
+def insert_cpp_header(filename, file_lines, start_year, end_year):
+ header_lines = get_cpp_header_lines_to_insert(start_year, end_year)
+ for line in header_lines:
+ file_lines.insert(0, line)
+ write_file_lines(filename, file_lines)
+
+def exec_insert_header(filename, style):
+ file_lines = read_file_lines(filename)
+ if file_already_has_core_copyright(file_lines):
+ sys.exit('*** %s already has a copyright by The Bitcoin Core developers'
+ % (filename))
+ start_year, end_year = get_git_change_year_range(filename)
+ if style == 'python':
+ insert_python_header(filename, file_lines, start_year, end_year)
+ else:
+ insert_cpp_header(filename, file_lines, start_year, end_year)
+
+################################################################################
+# insert cmd
+################################################################################
+
+INSERT_USAGE = """
+Inserts a copyright header for "The Bitcoin Core developers" at the top of the
+file in either Python or C++ style as determined by the file extension. If the
+file is a Python file and it has a '#!' starting the first line, the header is
+inserted in the line below it.
+
+The copyright dates will be set to be:
+
+"<year_introduced>-<current_year>"
+
+where <year_introduced> is according to the 'git log' history. If
+<year_introduced> is equal to <current_year>, the date will be set to be:
+
+"<current_year>"
+
+If the file already has a copyright for "The Bitcoin Core developers", the
+script will exit.
+
+Usage:
+ $ ./copyright_header.py insert <file>
+
+Arguments:
+ <file> - A source file in the bitcoin repository.
+"""
+
+def insert_cmd(argv):
+ if len(argv) != 3:
+ sys.exit(INSERT_USAGE)
+
+ filename = argv[2]
+ if not os.path.isfile(filename):
+ sys.exit("*** bad filename: %s" % filename)
+ _, extension = os.path.splitext(filename)
+ if extension not in ['.h', '.cpp', '.cc', '.c', '.py']:
+ sys.exit("*** cannot insert for file extension %s" % extension)
+
+ if extension == '.py':
+ style = 'python'
+ else:
+ style = 'cpp'
+ exec_insert_header(filename, style)
+
+################################################################################
+# UI
+################################################################################
+
+USAGE = """
+copyright_header.py - utilities for managing copyright headers of 'The Bitcoin
+Core developers' in repository source files.
+
+Usage:
+ $ ./copyright_header <subcommand>
+
+Subcommands:
+ report
+ update
+ insert
+
+To see subcommand usage, run them without arguments.
+"""
+
+SUBCOMMANDS = ['report', 'update', 'insert']
+
+if __name__ == "__main__":
+ if len(sys.argv) == 1:
+ sys.exit(USAGE)
+ subcommand = sys.argv[1]
+ if subcommand not in SUBCOMMANDS:
+ sys.exit(USAGE)
+ if subcommand == 'report':
+ report_cmd(sys.argv)
+ elif subcommand == 'update':
+ update_cmd(sys.argv)
+ elif subcommand == 'insert':
+ insert_cmd(sys.argv)
diff --git a/contrib/devtools/fix-copyright-headers.py b/contrib/devtools/fix-copyright-headers.py
deleted file mode 100755
index b6414a551f..0000000000
--- a/contrib/devtools/fix-copyright-headers.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-'''
-Run this script to update all the copyright headers of files
-that were changed this year.
-
-For example:
-
-// Copyright (c) 2009-2012 The Bitcoin Core developers
-
-it will change it to
-
-// Copyright (c) 2009-2015 The Bitcoin Core developers
-'''
-import os
-import time
-import re
-
-year = time.gmtime()[0]
-CMD_GIT_DATE = 'git log --format=@%%at -1 %s | date +"%%Y" -u -f -'
-CMD_REGEX= "perl -pi -e 's/(20\d\d)(?:-20\d\d)? The Bitcoin/$1-%s The Bitcoin/' %s"
-REGEX_CURRENT= re.compile("%s The Bitcoin" % year)
-CMD_LIST_FILES= "find %s | grep %s"
-
-FOLDERS = ["./qa", "./src"]
-EXTENSIONS = [".cpp",".h", ".py"]
-
-def get_git_date(file_path):
- r = os.popen(CMD_GIT_DATE % file_path)
- for l in r:
- # Result is one line, so just return
- return l.replace("\n","")
- return ""
-
-n=1
-for folder in FOLDERS:
- for extension in EXTENSIONS:
- for file_path in os.popen(CMD_LIST_FILES % (folder, extension)):
- file_path = os.getcwd() + file_path[1:-1]
- if file_path.endswith(extension):
- git_date = get_git_date(file_path)
- if str(year) == git_date:
- # Only update if current year is not found
- if REGEX_CURRENT.search(open(file_path, "r").read()) is None:
- print n,"Last git edit", git_date, "-", file_path
- os.popen(CMD_REGEX % (year,file_path))
- n = n + 1
diff --git a/contrib/devtools/gen-manpages.sh b/contrib/devtools/gen-manpages.sh
new file mode 100755
index 0000000000..967717e1e0
--- /dev/null
+++ b/contrib/devtools/gen-manpages.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+TOPDIR=${TOPDIR:-$(git rev-parse --show-toplevel)}
+SRCDIR=${SRCDIR:-$TOPDIR/src}
+MANDIR=${MANDIR:-$TOPDIR/doc/man}
+
+BITCOIND=${BITCOIND:-$SRCDIR/bitcoind}
+BITCOINCLI=${BITCOINCLI:-$SRCDIR/bitcoin-cli}
+BITCOINTX=${BITCOINTX:-$SRCDIR/bitcoin-tx}
+BITCOINQT=${BITCOINQT:-$SRCDIR/qt/bitcoin-qt}
+
+[ ! -x $BITCOIND ] && echo "$BITCOIND not found or not executable." && exit 1
+
+# The autodetected version git tag can screw up manpage output a little bit
+BTCVER=($($BITCOINCLI --version | head -n1 | awk -F'[ -]' '{ print $6, $7 }'))
+
+# Create a footer file with copyright content.
+# This gets autodetected fine for bitcoind if --version-string is not set,
+# but has different outcomes for bitcoin-qt and bitcoin-cli.
+echo "[COPYRIGHT]" > footer.h2m
+$BITCOIND --version | sed -n '1!p' >> footer.h2m
+
+for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $BITCOINQT; do
+ cmdname="${cmd##*/}"
+ help2man -N --version-string=${BTCVER[0]} --include=footer.h2m -o ${MANDIR}/${cmdname}.1 ${cmd}
+ sed -i "s/\\\-${BTCVER[1]}//g" ${MANDIR}/${cmdname}.1
+done
+
+rm -f footer.h2m
diff --git a/contrib/devtools/git-subtree-check.sh b/contrib/devtools/git-subtree-check.sh
index 1cb82fe682..2384d66cad 100755
--- a/contrib/devtools/git-subtree-check.sh
+++ b/contrib/devtools/git-subtree-check.sh
@@ -1,4 +1,7 @@
#!/bin/sh
+# 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.
DIR="$1"
COMMIT="$2"
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index f82362fe41..8fce648fc2 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016 Bitcoin Core Developers
+# Copyright (c) 2016-2017 Bitcoin Core Developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,9 +15,10 @@
# In case of a clean merge that is accepted by the user, the local branch with
# name $BRANCH is overwritten with the merged result, and optionally pushed.
from __future__ import division,print_function,unicode_literals
-import os,sys
+import os
from sys import stdin,stdout,stderr
import argparse
+import hashlib
import subprocess
import json,codecs
try:
@@ -69,6 +70,67 @@ def ask_prompt(text):
print("",file=stderr)
return reply
+def get_symlink_files():
+ files = sorted(subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', 'HEAD']).splitlines())
+ ret = []
+ for f in files:
+ if (int(f.decode('utf-8').split(" ")[0], 8) & 0o170000) == 0o120000:
+ ret.append(f.decode('utf-8').split("\t")[1])
+ return ret
+
+def tree_sha512sum(commit='HEAD'):
+ # request metadata for entire tree, recursively
+ files = []
+ blob_by_name = {}
+ for line in subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', commit]).splitlines():
+ name_sep = line.index(b'\t')
+ metadata = line[:name_sep].split() # perms, 'blob', blobid
+ assert(metadata[1] == b'blob')
+ name = line[name_sep+1:]
+ files.append(name)
+ blob_by_name[name] = metadata[2]
+
+ files.sort()
+ # open connection to git-cat-file in batch mode to request data for all blobs
+ # this is much faster than launching it per file
+ p = subprocess.Popen([GIT, 'cat-file', '--batch'], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
+ overall = hashlib.sha512()
+ for f in files:
+ blob = blob_by_name[f]
+ # request blob
+ p.stdin.write(blob + b'\n')
+ p.stdin.flush()
+ # read header: blob, "blob", size
+ reply = p.stdout.readline().split()
+ assert(reply[0] == blob and reply[1] == b'blob')
+ size = int(reply[2])
+ # hash the blob data
+ intern = hashlib.sha512()
+ ptr = 0
+ while ptr < size:
+ bs = min(65536, size - ptr)
+ piece = p.stdout.read(bs)
+ if len(piece) == bs:
+ intern.update(piece)
+ else:
+ raise IOError('Premature EOF reading git cat-file output')
+ ptr += bs
+ dig = intern.hexdigest()
+ assert(p.stdout.read(1) == b'\n') # ignore LF that follows blob data
+ # update overall hash with file hash
+ overall.update(dig.encode("utf-8"))
+ overall.update(" ".encode("utf-8"))
+ overall.update(f)
+ overall.update("\n".encode("utf-8"))
+ p.stdin.close()
+ if p.wait():
+ raise IOError('Non-zero return value executing git cat-file')
+ return overall.hexdigest()
+
+def print_merge_details(pull, title, branch, base_branch, head_branch):
+ print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET))
+ subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch])
+
def parse_arguments():
epilog = '''
In addition, you can set the following git configuration variables:
@@ -112,7 +174,7 @@ def main():
info = retrieve_pr_info(repo,pull)
if info is None:
exit(1)
- title = info['title']
+ title = info['title'].strip()
# precedence order for destination branch argument:
# - command line argument
# - githubmerge.branch setting
@@ -157,6 +219,9 @@ def main():
subprocess.check_call([GIT,'checkout','-q','-b',local_merge_branch])
try:
+ # Go up to the repository's root.
+ toplevel = subprocess.check_output([GIT,'rev-parse','--show-toplevel']).strip()
+ os.chdir(toplevel)
# Create unsigned merge commit.
if title:
firstline = 'Merge #%s: %s' % (pull,title)
@@ -175,14 +240,30 @@ def main():
print("ERROR: Creating merge failed (already merged?).",file=stderr)
exit(4)
- print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET))
- subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch])
+ symlink_files = get_symlink_files()
+ for f in symlink_files:
+ print("ERROR: File %s was a symlink" % f)
+ if len(symlink_files) > 0:
+ exit(4)
+
+ # Put tree SHA512 into the message
+ try:
+ first_sha512 = tree_sha512sum()
+ message += '\n\nTree-SHA512: ' + first_sha512
+ except subprocess.CalledProcessError as e:
+ printf("ERROR: Unable to compute tree hash")
+ exit(4)
+ try:
+ subprocess.check_call([GIT,'commit','--amend','-m',message.encode('utf-8')])
+ except subprocess.CalledProcessError as e:
+ printf("ERROR: Cannot update message.",file=stderr)
+ exit(4)
+
+ print_merge_details(pull, title, branch, base_branch, head_branch)
print()
+
# Run test command if configured.
if testcmd:
- # Go up to the repository's root.
- toplevel = subprocess.check_output([GIT,'rev-parse','--show-toplevel']).strip()
- os.chdir(toplevel)
if subprocess.call(testcmd,shell=True):
print("ERROR: Running %s failed." % testcmd,file=stderr)
exit(5)
@@ -197,12 +278,6 @@ def main():
print("Difference with github ignored.",file=stderr)
else:
exit(6)
- reply = ask_prompt("Press 'd' to accept the diff.")
- if reply.lower() == 'd':
- print("Diff accepted.",file=stderr)
- else:
- print("ERROR: Diff rejected.",file=stderr)
- exit(6)
else:
# Verify the result manually.
print("Dropping you on a shell so you can try building/testing the merged source.",file=stderr)
@@ -211,24 +286,26 @@ def main():
if os.path.isfile('/etc/debian_version'): # Show pull number on Debian default prompt
os.putenv('debian_chroot',pull)
subprocess.call([BASH,'-i'])
- reply = ask_prompt("Type 'm' to accept the merge.")
- if reply.lower() == 'm':
- print("Merge accepted.",file=stderr)
- else:
- print("ERROR: Merge rejected.",file=stderr)
- exit(7)
+
+ second_sha512 = tree_sha512sum()
+ if first_sha512 != second_sha512:
+ print("ERROR: Tree hash changed unexpectedly",file=stderr)
+ exit(8)
# Sign the merge commit.
- reply = ask_prompt("Type 's' to sign off on the merge.")
- if reply == 's':
- try:
- subprocess.check_call([GIT,'commit','-q','--gpg-sign','--amend','--no-edit'])
- except subprocess.CalledProcessError as e:
- print("Error signing, exiting.",file=stderr)
+ print_merge_details(pull, title, branch, base_branch, head_branch)
+ while True:
+ reply = ask_prompt("Type 's' to sign off on the above merge, or 'x' to reject and exit.").lower()
+ if reply == 's':
+ try:
+ subprocess.check_call([GIT,'commit','-q','--gpg-sign','--amend','--no-edit'])
+ break
+ except subprocess.CalledProcessError as e:
+ print("Error signing, exiting.",file=stderr)
+ exit(1)
+ elif reply == 'x':
+ print("Not signing off on merge, exiting.",file=stderr)
exit(1)
- else:
- print("Not signing off on merge, exiting.",file=stderr)
- exit(1)
# Put the result in branch.
subprocess.check_call([GIT,'checkout','-q',branch])
@@ -242,9 +319,13 @@ def main():
subprocess.call([GIT,'branch','-q','-D',local_merge_branch],stderr=devnull)
# Push the result.
- reply = ask_prompt("Type 'push' to push the result to %s, branch %s." % (host_repo,branch))
- if reply.lower() == 'push':
- subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch])
+ while True:
+ reply = ask_prompt("Type 'push' to push the result to %s, branch %s, or 'x' to exit without pushing." % (host_repo,branch)).lower()
+ if reply == 'push':
+ subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch])
+ break
+ elif reply == 'x':
+ exit(1)
if __name__ == '__main__':
main()
diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py
index 799e0cc7d0..9286ab731f 100755
--- a/contrib/devtools/optimize-pngs.py
+++ b/contrib/devtools/optimize-pngs.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python
+# Copyright (c) 2014-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.
'''
Run this script every time you change one of the png files. Using pngcrush, it will optimize the png files, remove various color profiles, remove ancillary chunks (alla) and text chunks (text).
#pngcrush -brute -ow -rem gAMA -rem cHRM -rem iCCP -rem sRGB -rem alla -rem text
@@ -36,7 +39,7 @@ for folder in folders:
if extension.lower() == '.png':
print("optimizing "+file+"..."),
file_path = os.path.join(absFolder, file)
- fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)};
+ fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)}
fileMetaMap['contentHashPre'] = content_hash(file_path)
pngCrushOutput = ""
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index 301fea85c1..c90541e271 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -1,4 +1,7 @@
-#!/usr/bin/python2
+#!/usr/bin/env python
+# Copyright (c) 2015-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.
'''
Perform basic ELF security checks on a series of executables.
Exit status will be 0 if successful, and the program will be silent.
@@ -12,6 +15,7 @@ import os
READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump')
+NONFATAL = {'HIGH_ENTROPY_VA'} # checks which are non-fatal for now but only generate a warning
def check_ELF_PIE(executable):
'''
@@ -114,26 +118,50 @@ def check_ELF_Canary(executable):
def get_PE_dll_characteristics(executable):
'''
- Get PE DllCharacteristics bits
+ Get PE DllCharacteristics bits.
+ Returns a tuple (arch,bits) where arch is 'i386:x86-64' or 'i386'
+ and bits is the DllCharacteristics value.
'''
p = subprocess.Popen([OBJDUMP_CMD, '-x', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Error opening file')
+ arch = ''
+ bits = 0
for line in stdout.split('\n'):
tokens = line.split()
+ if len(tokens)>=2 and tokens[0] == 'architecture:':
+ arch = tokens[1].rstrip(',')
if len(tokens)>=2 and tokens[0] == 'DllCharacteristics':
- return int(tokens[1],16)
- return 0
+ bits = int(tokens[1],16)
+ return (arch,bits)
+IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020
+IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040
+IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100
-def check_PE_PIE(executable):
+def check_PE_DYNAMIC_BASE(executable):
'''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)'''
- return bool(get_PE_dll_characteristics(executable) & 0x40)
+ (arch,bits) = get_PE_dll_characteristics(executable)
+ reqbits = IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
+ return (bits & reqbits) == reqbits
+
+# On 64 bit, must support high-entropy 64-bit address space layout randomization in addition to DYNAMIC_BASE
+# to have secure ASLR.
+def check_PE_HIGH_ENTROPY_VA(executable):
+ '''PIE: DllCharacteristics bit 0x20 signifies high-entropy ASLR'''
+ (arch,bits) = get_PE_dll_characteristics(executable)
+ if arch == 'i386:x86-64':
+ reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
+ else: # Unnecessary on 32-bit
+ assert(arch == 'i386')
+ reqbits = 0
+ return (bits & reqbits) == reqbits
def check_PE_NX(executable):
'''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)'''
- return bool(get_PE_dll_characteristics(executable) & 0x100)
+ (arch,bits) = get_PE_dll_characteristics(executable)
+ return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
CHECKS = {
'ELF': [
@@ -143,7 +171,8 @@ CHECKS = {
('Canary', check_ELF_Canary)
],
'PE': [
- ('PIE', check_PE_PIE),
+ ('DYNAMIC_BASE', check_PE_DYNAMIC_BASE),
+ ('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA),
('NX', check_PE_NX)
]
}
@@ -168,12 +197,18 @@ if __name__ == '__main__':
continue
failed = []
+ warning = []
for (name, func) in CHECKS[etype]:
if not func(filename):
- failed.append(name)
+ if name in NONFATAL:
+ warning.append(name)
+ else:
+ failed.append(name)
if failed:
print('%s: failed %s' % (filename, ' '.join(failed)))
retval = 1
+ if warning:
+ print('%s: warning %s' % (filename, ' '.join(warning)))
except IOError:
print('%s: cannot open' % filename)
retval = 1
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index e26c0fbb94..8f8685006e 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python
# Copyright (c) 2014 Wladimir J. van der Laan
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index fed7626aab..18f9835faa 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -1,10 +1,12 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
+# Copyright (c) 2015-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.
'''
Test script for security-check.py
'''
from __future__ import division,print_function
import subprocess
-import sys
import unittest
def write_testcode(filename):
diff --git a/contrib/devtools/update-translations.py b/contrib/devtools/update-translations.py
index 2b6e807b47..2011841005 100755
--- a/contrib/devtools/update-translations.py
+++ b/contrib/devtools/update-translations.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# Copyright (c) 2014 Wladimir J. van der Laan
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -65,6 +65,14 @@ def split_format_specifiers(specifiers):
else:
other.append(s)
+ # If both numeric format specifiers and "others" are used, assume we're dealing
+ # with a Qt-formatted message. In the case of Qt formatting (see https://doc.qt.io/qt-5/qstring.html#arg)
+ # only numeric formats are replaced at all. This means "(percentage: %1%)" is valid, without needing
+ # any kind of escaping that would be necessary for strprintf. Without this, this function
+ # would wrongly detect '%)' as a printf format specifier.
+ if numeric:
+ other = []
+
# numeric (Qt) can be present in any order, others (strprintf) must be in specified order
return set(numeric),other
diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh
new file mode 100755
index 0000000000..6ee5df4703
--- /dev/null
+++ b/contrib/gitian-build.sh
@@ -0,0 +1,392 @@
+# Copyright (c) 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.
+
+# What to do
+sign=false
+verify=false
+build=false
+setupenv=false
+
+# Systems to build
+linux=true
+windows=true
+osx=true
+
+# Other Basic variables
+SIGNER=
+VERSION=
+commit=false
+url=https://github.com/bitcoin/bitcoin
+proc=2
+mem=2000
+lxc=true
+osslTarUrl=http://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz
+osslPatchUrl=https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch
+scriptName=$(basename -- "$0")
+signProg="gpg --detach-sign"
+commitFiles=true
+
+# Help Message
+read -d '' usage <<- EOF
+Usage: $scriptName [-c|u|v|b|s|B|o|h|j|m|] signer version
+
+Run this script from the directory containing the bitcoin, gitian-builder, gitian.sigs, and bitcoin-detached-sigs.
+
+Arguments:
+signer GPG signer to sign each build assert file
+version Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified
+
+Options:
+-c|--commit Indicate that the version argument is for a commit or branch
+-u|--url Specify the URL of the repository. Default is https://github.com/bitcoin/bitcoin
+-v|--verify Verify the gitian build
+-b|--build Do a gitian build
+-s|--sign Make signed binaries for Windows and Mac OSX
+-B|--buildsign Build both signed and unsigned binaries
+-o|--os Specify which Operating Systems the build is for. Default is lwx. l for linux, w for windows, x for osx
+-j Number of processes to use. Default 2
+-m Memory to allocate in MiB. Default 2000
+--kvm Use KVM instead of LXC
+--setup Setup the gitian building environment. Uses KVM. If you want to use lxc, use the --lxc option. Only works on Debian-based systems (Ubuntu, Debian)
+--detach-sign Create the assert file for detached signing. Will not commit anything.
+--no-commit Do not commit anything to git
+-h|--help Print this help message
+EOF
+
+# Get options and arguments
+while :; do
+ case $1 in
+ # Verify
+ -v|--verify)
+ verify=true
+ ;;
+ # Build
+ -b|--build)
+ build=true
+ ;;
+ # Sign binaries
+ -s|--sign)
+ sign=true
+ ;;
+ # Build then Sign
+ -B|--buildsign)
+ sign=true
+ build=true
+ ;;
+ # PGP Signer
+ -S|--signer)
+ if [ -n "$2" ]
+ then
+ SIGNER=$2
+ shift
+ else
+ echo 'Error: "--signer" requires a non-empty argument.'
+ exit 1
+ fi
+ ;;
+ # Operating Systems
+ -o|--os)
+ if [ -n "$2" ]
+ then
+ linux=false
+ windows=false
+ osx=false
+ if [[ "$2" = *"l"* ]]
+ then
+ linux=true
+ fi
+ if [[ "$2" = *"w"* ]]
+ then
+ windows=true
+ fi
+ if [[ "$2" = *"x"* ]]
+ then
+ osx=true
+ fi
+ shift
+ else
+ echo 'Error: "--os" requires an argument containing an l (for linux), w (for windows), or x (for Mac OSX)\n'
+ exit 1
+ fi
+ ;;
+ # Help message
+ -h|--help)
+ echo "$usage"
+ exit 0
+ ;;
+ # Commit or branch
+ -c|--commit)
+ commit=true
+ ;;
+ # Number of Processes
+ -j)
+ if [ -n "$2" ]
+ then
+ proc=$2
+ shift
+ else
+ echo 'Error: "-j" requires an argument'
+ exit 1
+ fi
+ ;;
+ # Memory to allocate
+ -m)
+ if [ -n "$2" ]
+ then
+ mem=$2
+ shift
+ else
+ echo 'Error: "-m" requires an argument'
+ exit 1
+ fi
+ ;;
+ # URL
+ -u)
+ if [ -n "$2" ]
+ then
+ url=$2
+ shift
+ else
+ echo 'Error: "-u" requires an argument'
+ exit 1
+ fi
+ ;;
+ # kvm
+ --kvm)
+ lxc=false
+ ;;
+ # Detach sign
+ --detach-sign)
+ signProg="true"
+ commitFiles=false
+ ;;
+ # Commit files
+ --no-commit)
+ commitFiles=false
+ ;;
+ # Setup
+ --setup)
+ setup=true
+ ;;
+ *) # Default case: If no more options then break out of the loop.
+ break
+ esac
+ shift
+done
+
+# Set up LXC
+if [[ $lxc = true ]]
+then
+ export USE_LXC=1
+ export LXC_BRIDGE=lxcbr0
+ sudo ifconfig lxcbr0 up 10.0.2.2
+fi
+
+# Check for OSX SDK
+if [[ ! -e "gitian-builder/inputs/MacOSX10.11.sdk.tar.gz" && $osx == true ]]
+then
+ echo "Cannot build for OSX, SDK does not exist. Will build for other OSes"
+ osx=false
+fi
+
+# Get signer
+if [[ -n"$1" ]]
+then
+ SIGNER=$1
+ shift
+fi
+
+# Get version
+if [[ -n "$1" ]]
+then
+ VERSION=$1
+ COMMIT=$VERSION
+ shift
+fi
+
+# Check that a signer is specified
+if [[ $SIGNER == "" ]]
+then
+ echo "$scriptName: Missing signer."
+ echo "Try $scriptName --help for more information"
+ exit 1
+fi
+
+# Check that a version is specified
+if [[ $VERSION == "" ]]
+then
+ echo "$scriptName: Missing version."
+ echo "Try $scriptName --help for more information"
+ exit 1
+fi
+
+# Add a "v" if no -c
+if [[ $commit = false ]]
+then
+ COMMIT="v${VERSION}"
+fi
+echo ${COMMIT}
+
+# Setup build environment
+if [[ $setup = true ]]
+then
+ sudo apt-get install ruby apache2 git apt-cacher-ng python-vm-builder qemu-kvm qemu-utils
+ git clone https://github.com/bitcoin-core/gitian.sigs.git
+ git clone https://github.com/bitcoin-core/bitcoin-detached-sigs.git
+ git clone https://github.com/devrandom/gitian-builder.git
+ pushd ./gitian-builder
+ if [[ -n "$USE_LXC" ]]
+ then
+ sudo apt-get install lxc
+ bin/make-base-vm --suite trusty --arch amd64 --lxc
+ else
+ bin/make-base-vm --suite trusty --arch amd64
+ fi
+ popd
+fi
+
+# Set up build
+pushd ./bitcoin
+git fetch
+git checkout ${COMMIT}
+popd
+
+# Build
+if [[ $build = true ]]
+then
+ # Make output folder
+ mkdir -p ./bitcoin-binaries/${VERSION}
+
+ # Build Dependencies
+ echo ""
+ echo "Building Dependencies"
+ echo ""
+ pushd ./gitian-builder
+ mkdir -p inputs
+ wget -N -P inputs $osslPatchUrl
+ wget -N -P inputs $osslTarUrl
+ make -C ../bitcoin/depends download SOURCES_PATH=`pwd`/cache/common
+
+ # Linux
+ if [[ $linux = true ]]
+ then
+ echo ""
+ echo "Compiling ${VERSION} Linux"
+ echo ""
+ ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/${VERSION}
+ fi
+ # Windows
+ if [[ $windows = true ]]
+ then
+ echo ""
+ echo "Compiling ${VERSION} Windows"
+ echo ""
+ ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+ mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz
+ mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../bitcoin-binaries/${VERSION}
+ fi
+ # Mac OSX
+ if [[ $osx = true ]]
+ then
+ echo ""
+ echo "Compiling ${VERSION} Mac OSX"
+ echo ""
+ ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
+ mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz
+ mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../bitcoin-binaries/${VERSION}
+ fi
+ popd
+
+ if [[ $commitFiles = true ]]
+ then
+ # Commit to gitian.sigs repo
+ echo ""
+ echo "Committing ${VERSION} Unsigned Sigs"
+ echo ""
+ pushd gitian.sigs
+ git add ${VERSION}-linux/${SIGNER}
+ git add ${VERSION}-win-unsigned/${SIGNER}
+ git add ${VERSION}-osx-unsigned/${SIGNER}
+ git commit -a -m "Add ${VERSION} unsigned sigs for ${SIGNER}"
+ popd
+ fi
+fi
+
+# Verify the build
+if [[ $verify = true ]]
+then
+ # Linux
+ pushd ./gitian-builder
+ echo ""
+ echo "Verifying v${VERSION} Linux"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ # Windows
+ echo ""
+ echo "Verifying v${VERSION} Windows"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+ # Mac OSX
+ echo ""
+ echo "Verifying v${VERSION} Mac OSX"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
+ # Signed Windows
+ echo ""
+ echo "Verifying v${VERSION} Signed Windows"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ # Signed Mac OSX
+ echo ""
+ echo "Verifying v${VERSION} Signed Mac OSX"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ popd
+fi
+
+# Sign binaries
+if [[ $sign = true ]]
+then
+
+ pushd ./gitian-builder
+ # Sign Windows
+ if [[ $windows = true ]]
+ then
+ echo ""
+ echo "Signing ${VERSION} Windows"
+ echo ""
+ ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
+ mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/${VERSION}
+ mv build/out/bitcoin-*win32-setup.exe ../bitcoin-binaries/${VERSION}
+ fi
+ # Sign Mac OSX
+ if [[ $osx = true ]]
+ then
+ echo ""
+ echo "Signing ${VERSION} Mac OSX"
+ echo ""
+ ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/${VERSION}/bitcoin-${VERSION}-osx.dmg
+ fi
+ popd
+
+ if [[ $commitFiles = true ]]
+ then
+ # Commit Sigs
+ pushd gitian.sigs
+ echo ""
+ echo "Committing ${VERSION} Signed Sigs"
+ echo ""
+ git add ${VERSION}-win-signed/${SIGNER}
+ git add ${VERSION}-osx-signed/${SIGNER}
+ git commit -a -m "Add ${VERSION} signed binary sigs for ${SIGNER}"
+ popd
+ fi
+fi
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index aaff127b5e..3da8510cfb 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -1,5 +1,5 @@
---
-name: "bitcoin-linux-0.13"
+name: "bitcoin-linux-0.15"
enable_cache: true
suites:
- "trusty"
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index 318fb03ef2..206db7c19e 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -1,5 +1,5 @@
---
-name: "bitcoin-osx-0.13"
+name: "bitcoin-osx-0.15"
enable_cache: true
suites:
- "trusty"
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index 63177375ef..1d4d70494b 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -1,5 +1,5 @@
---
-name: "bitcoin-win-0.13"
+name: "bitcoin-win-0.15"
enable_cache: true
suites:
- "trusty"
@@ -27,7 +27,7 @@ remotes:
files: []
script: |
WRAP_DIR=$HOME/wrapped
- HOSTS="x86_64-w64-mingw32 i686-w64-mingw32"
+ HOSTS="i686-w64-mingw32 x86_64-w64-mingw32"
CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests"
FAKETIME_HOST_PROGS="g++ ar ranlib nm windres strip objcopy"
FAKETIME_PROGS="date makensis zip"
@@ -147,6 +147,7 @@ script: |
make ${MAKEOPTS} -C src check-security
make deploy
make install DESTDIR=${INSTALLPATH}
+ rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe
cp -f bitcoin-*setup*.exe $OUTDIR/
cd installed
mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/
@@ -160,9 +161,11 @@ script: |
cd ../../
rm -rf distsrc-${i}
done
- cd $OUTDIR
- rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe
- find . -name "*-setup-unsigned.exe" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz
+ cp -rf contrib/windeploy $BUILD_DIR
+ cd $BUILD_DIR/windeploy
+ mkdir unsigned
+ cp $OUTDIR/bitcoin-*setup-unsigned.exe unsigned/
+ find . | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz
mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.zip ${OUTDIR}/${DISTNAME}-win64-debug.zip
mv ${OUTDIR}/${DISTNAME}-i686-*-debug.zip ${OUTDIR}/${DISTNAME}-win32-debug.zip
mv ${OUTDIR}/${DISTNAME}-x86_64-*.zip ${OUTDIR}/${DISTNAME}-win64.zip
diff --git a/contrib/gitian-keys/README.md b/contrib/gitian-keys/README.md
new file mode 100644
index 0000000000..439910330d
--- /dev/null
+++ b/contrib/gitian-keys/README.md
@@ -0,0 +1,16 @@
+PGP keys
+========
+
+This folder contains the public keys of developers and active contributors.
+
+The keys are mainly used to sign git commits or the build results of gitian
+builds.
+
+You can import the keys into gpg as follows. Also, make sure to fetch the
+latest version from the key server to see if any key was revoked in the
+meantime.
+
+```sh
+gpg --import ./*.pgp
+gpg --refresh-keys
+```
diff --git a/contrib/gitian-keys/btcdrak-key.pgp b/contrib/gitian-keys/btcdrak-key.pgp
index 60d76c0ec7..f00dc729d5 100644
--- a/contrib/gitian-keys/btcdrak-key.pgp
+++ b/contrib/gitian-keys/btcdrak-key.pgp
Binary files differ
diff --git a/contrib/gitian-keys/jtimon-key.pgp b/contrib/gitian-keys/jtimon-key.pgp
new file mode 100644
index 0000000000..88d0de1503
--- /dev/null
+++ b/contrib/gitian-keys/jtimon-key.pgp
Binary files differ
diff --git a/contrib/init/README.md b/contrib/init/README.md
index eb5d30acce..1a949f3c07 100644
--- a/contrib/init/README.md
+++ b/contrib/init/README.md
@@ -1,12 +1,12 @@
Sample configuration files for:
-
+```
SystemD: bitcoind.service
Upstart: bitcoind.conf
OpenRC: bitcoind.openrc
bitcoind.openrcconf
CentOS: bitcoind.init
OS X: org.bitcoin.bitcoind.plist
-
+```
have been made available to assist packagers in creating node packages here.
See doc/init.md for more information.
diff --git a/contrib/linearize/README.md b/contrib/linearize/README.md
index 06f278f3b3..f2a2ab2768 100644
--- a/contrib/linearize/README.md
+++ b/contrib/linearize/README.md
@@ -1,33 +1,55 @@
# Linearize
-Construct a linear, no-fork, best version of the blockchain.
+Construct a linear, no-fork, best version of the Bitcoin blockchain. The scripts
+run using Python 3 but are compatible with Python 2.
## Step 1: Download hash list
$ ./linearize-hashes.py linearize.cfg > hashlist.txt
Required configuration file settings for linearize-hashes:
-* RPC: rpcuser, rpcpassword
+* RPC: `datadir` (Required if `rpcuser` and `rpcpassword` are not specified)
+* RPC: `rpcuser`, `rpcpassword` (Required if `datadir` is not specified)
Optional config file setting for linearize-hashes:
-* RPC: host, port
-* Block chain: min_height, max_height
+* RPC: `host` (Default: `127.0.0.1`)
+* RPC: `port` (Default: `8332`)
+* Blockchain: `min_height`, `max_height`
+* `rev_hash_bytes`: If true, the written block hash list will be
+byte-reversed. (In other words, the hash returned by getblockhash will have its
+bytes reversed.) False by default. Intended for generation of
+standalone hash lists but safe to use with linearize-data.py, which will output
+the same data no matter which byte format is chosen.
+
+The `linearize-hashes` script requires a connection, local or remote, to a
+JSON-RPC server. Running `bitcoind` or `bitcoin-qt -server` will be sufficient.
## Step 2: Copy local block data
$ ./linearize-data.py linearize.cfg
Required configuration file settings:
-* "input": bitcoind blocks/ directory containing blkNNNNN.dat
-* "hashlist": text file containing list of block hashes, linearized-hashes.py
-output.
-* "output_file": bootstrap.dat
+* `output_file`: The file that will contain the final blockchain.
or
-* "output": output directory for linearized blocks/blkNNNNN.dat output
+* `output`: Output directory for linearized `blocks/blkNNNNN.dat` output.
Optional config file setting for linearize-data:
-* "netmagic": network magic number
-* "max_out_sz": maximum output file size (default `1000*1000*1000`)
-* "split_timestamp": Split files when a new month is first seen, in addition to
-reaching a maximum file size.
-* "file_timestamp": Set each file's last-modified time to that of the
-most recent block in that file.
+* `debug_output`: Some printouts may not always be desired. If true, such output
+will be printed.
+* `file_timestamp`: Set each file's last-accessed and last-modified times,
+respectively, to the current time and to the timestamp of the most recent block
+written to the script's blockchain.
+* `genesis`: The hash of the genesis block in the blockchain.
+* `input`: bitcoind blocks/ directory containing blkNNNNN.dat
+* `hashlist`: text file containing list of block hashes created by
+linearize-hashes.py.
+* `max_out_sz`: Maximum size for files created by the `output_file` option.
+(Default: `1000*1000*1000 bytes`)
+* `netmagic`: Network magic number.
+* `out_of_order_cache_sz`: If out-of-order blocks are being read, the block can
+be written to a cache so that the blockchain doesn't have to be seeked again.
+This option specifies the cache size. (Default: `100*1000*1000 bytes`)
+* `rev_hash_bytes`: If true, the block hash list written by linearize-hashes.py
+will be byte-reversed when read by linearize-data.py. See the linearize-hashes
+entry for more information.
+* `split_timestamp`: Split blockchain files when a new month is first seen, in
+addition to reaching a maximum file size (`max_out_sz`).
diff --git a/contrib/linearize/example-linearize.cfg b/contrib/linearize/example-linearize.cfg
index 38da02e66c..d019b06b6c 100644
--- a/contrib/linearize/example-linearize.cfg
+++ b/contrib/linearize/example-linearize.cfg
@@ -1,7 +1,7 @@
-
# bitcoind RPC settings (linearize-hashes)
rpcuser=someuser
rpcpassword=somepassword
+#datadir=~/.bitcoin
host=127.0.0.1
port=8332
#port=18332
@@ -21,9 +21,23 @@ input=/home/example/.bitcoin/blocks
#genesis=000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943
#input=/home/example/.bitcoin/testnet3/blocks
+# "output" option causes blockchain files to be written to the given location,
+# with "output_file" ignored. If not used, "output_file" is used instead.
+# output=/home/example/blockchain_directory
output_file=/home/example/Downloads/bootstrap.dat
hashlist=hashlist.txt
-split_year=1
-# Maxmimum size in bytes of out-of-order blocks cache in memory
+# Maximum size in bytes of out-of-order blocks cache in memory
out_of_order_cache_sz = 100000000
+
+# Do we want the reverse the hash bytes coming from getblockhash?
+rev_hash_bytes = False
+
+# On a new month, do we want to set the access and modify times of the new
+# blockchain file?
+file_timestamp = 0
+# Do we want to split the blockchain files given a new month or specific height?
+split_timestamp = 0
+
+# Do we want debug printouts?
+debug_output = False
diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py
index 0f6fde2a6e..afcec2b60a 100755
--- a/contrib/linearize/linearize-data.py
+++ b/contrib/linearize/linearize-data.py
@@ -1,30 +1,34 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# linearize-data.py: Construct a linear, no-fork version of the chain.
#
-# Copyright (c) 2013-2014 The Bitcoin Core developers
+# Copyright (c) 2013-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 print_function, division
-import json
import struct
import re
import os
import os.path
-import base64
-import httplib
import sys
import hashlib
import datetime
import time
from collections import namedtuple
+from binascii import hexlify, unhexlify
settings = {}
+##### Switch endian-ness #####
+def hex_switchEndian(s):
+ """ Switches the endianness of a hex string (in pairs of hex chars) """
+ pairList = [s[i:i+2].encode() for i in range(0, len(s), 2)]
+ return b''.join(pairList[::-1]).decode()
+
def uint32(x):
- return x & 0xffffffffL
+ return x & 0xffffffff
def bytereverse(x):
return uint32(( ((x) << 24) | (((x) << 8) & 0x00ff0000) |
@@ -35,14 +39,14 @@ def bufreverse(in_buf):
for i in range(0, len(in_buf), 4):
word = struct.unpack('@I', in_buf[i:i+4])[0]
out_words.append(struct.pack('@I', bytereverse(word)))
- return ''.join(out_words)
+ return b''.join(out_words)
def wordreverse(in_buf):
out_words = []
for i in range(0, len(in_buf), 4):
out_words.append(in_buf[i:i+4])
out_words.reverse()
- return ''.join(out_words)
+ return b''.join(out_words)
def calc_hdr_hash(blk_hdr):
hash1 = hashlib.sha256()
@@ -59,7 +63,7 @@ def calc_hash_str(blk_hdr):
hash = calc_hdr_hash(blk_hdr)
hash = bufreverse(hash)
hash = wordreverse(hash)
- hash_str = hash.encode('hex')
+ hash_str = hexlify(hash).decode('utf-8')
return hash_str
def get_blk_dt(blk_hdr):
@@ -69,17 +73,21 @@ def get_blk_dt(blk_hdr):
dt_ym = datetime.datetime(dt.year, dt.month, 1)
return (dt_ym, nTime)
+# When getting the list of block hashes, undo any byte reversals.
def get_block_hashes(settings):
blkindex = []
f = open(settings['hashlist'], "r")
for line in f:
line = line.rstrip()
+ if settings['rev_hash_bytes'] == 'true':
+ line = hex_switchEndian(line)
blkindex.append(line)
print("Read " + str(len(blkindex)) + " hashes")
return blkindex
+# The block map shouldn't give or receive byte-reversed hashes.
def mkblockmap(blkindex):
blkmap = {}
for height,hash in enumerate(blkindex):
@@ -126,7 +134,7 @@ class BlockDataCopier:
if not self.fileOutput and ((self.outsz + blockSizeOnDisk) > self.maxOutSz):
self.outF.close()
if self.setFileTime:
- os.utime(outFname, (int(time.time()), highTS))
+ os.utime(self.outFname, (int(time.time()), self.highTS))
self.outF = None
self.outFname = None
self.outFn = self.outFn + 1
@@ -134,12 +142,12 @@ class BlockDataCopier:
(blkDate, blkTS) = get_blk_dt(blk_hdr)
if self.timestampSplit and (blkDate > self.lastDate):
- print("New month " + blkDate.strftime("%Y-%m") + " @ " + hash_str)
- lastDate = blkDate
- if outF:
- outF.close()
- if setFileTime:
- os.utime(outFname, (int(time.time()), highTS))
+ print("New month " + blkDate.strftime("%Y-%m") + " @ " + self.hash_str)
+ self.lastDate = blkDate
+ if self.outF:
+ self.outF.close()
+ if self.setFileTime:
+ os.utime(self.outFname, (int(time.time()), self.highTS))
self.outF = None
self.outFname = None
self.outFn = self.outFn + 1
@@ -147,11 +155,11 @@ class BlockDataCopier:
if not self.outF:
if self.fileOutput:
- outFname = self.settings['output_file']
+ self.outFname = self.settings['output_file']
else:
- outFname = os.path.join(self.settings['output'], "blk%05d.dat" % self.outFn)
- print("Output file " + outFname)
- self.outF = open(outFname, "wb")
+ self.outFname = os.path.join(self.settings['output'], "blk%05d.dat" % self.outFn)
+ print("Output file " + self.outFname)
+ self.outF = open(self.outFname, "wb")
self.outF.write(inhdr)
self.outF.write(blk_hdr)
@@ -207,7 +215,7 @@ class BlockDataCopier:
inMagic = inhdr[:4]
if (inMagic != self.settings['netmagic']):
- print("Invalid magic: " + inMagic.encode('hex'))
+ print("Invalid magic: " + hexlify(inMagic).decode('utf-8'))
return
inLenLE = inhdr[4:]
su = struct.unpack("<I", inLenLE)
@@ -215,13 +223,16 @@ class BlockDataCopier:
blk_hdr = self.inF.read(80)
inExtent = BlockExtent(self.inFn, self.inF.tell(), inhdr, blk_hdr, inLen)
- hash_str = calc_hash_str(blk_hdr)
- if not hash_str in blkmap:
- print("Skipping unknown block " + hash_str)
+ self.hash_str = calc_hash_str(blk_hdr)
+ if not self.hash_str in blkmap:
+ # Because blocks can be written to files out-of-order as of 0.10, the script
+ # may encounter blocks it doesn't know about. Treat as debug output.
+ if settings['debug_output'] == 'true':
+ print("Skipping unknown block " + self.hash_str)
self.inF.seek(inLen, os.SEEK_CUR)
continue
- blkHeight = self.blkmap[hash_str]
+ blkHeight = self.blkmap[self.hash_str]
self.blkCountIn += 1
if self.blkCountOut == blkHeight:
@@ -265,6 +276,12 @@ if __name__ == '__main__':
settings[m.group(1)] = m.group(2)
f.close()
+ # Force hash byte format setting to be lowercase to make comparisons easier.
+ # Also place upfront in case any settings need to know about it.
+ if 'rev_hash_bytes' not in settings:
+ settings['rev_hash_bytes'] = 'false'
+ settings['rev_hash_bytes'] = settings['rev_hash_bytes'].lower()
+
if 'netmagic' not in settings:
settings['netmagic'] = 'f9beb4d9'
if 'genesis' not in settings:
@@ -278,15 +295,18 @@ if __name__ == '__main__':
if 'split_timestamp' not in settings:
settings['split_timestamp'] = 0
if 'max_out_sz' not in settings:
- settings['max_out_sz'] = 1000L * 1000 * 1000
+ settings['max_out_sz'] = 1000 * 1000 * 1000
if 'out_of_order_cache_sz' not in settings:
settings['out_of_order_cache_sz'] = 100 * 1000 * 1000
+ if 'debug_output' not in settings:
+ settings['debug_output'] = 'false'
- settings['max_out_sz'] = long(settings['max_out_sz'])
+ settings['max_out_sz'] = int(settings['max_out_sz'])
settings['split_timestamp'] = int(settings['split_timestamp'])
settings['file_timestamp'] = int(settings['file_timestamp'])
- settings['netmagic'] = settings['netmagic'].decode('hex')
+ settings['netmagic'] = unhexlify(settings['netmagic'].encode('utf-8'))
settings['out_of_order_cache_sz'] = int(settings['out_of_order_cache_sz'])
+ settings['debug_output'] = settings['debug_output'].lower()
if 'output_file' not in settings and 'output' not in settings:
print("Missing output file / directory")
@@ -295,9 +315,8 @@ if __name__ == '__main__':
blkindex = get_block_hashes(settings)
blkmap = mkblockmap(blkindex)
+ # Block hash map won't be byte-reversed. Neither should the genesis hash.
if not settings['genesis'] in blkmap:
print("Genesis block not found in hashlist")
else:
BlockDataCopier(settings, blkindex, blkmap).run()
-
-
diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py
index 854cf1f9ee..db8eb7021e 100755
--- a/contrib/linearize/linearize-hashes.py
+++ b/contrib/linearize/linearize-hashes.py
@@ -1,39 +1,55 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# linearize-hashes.py: List blocks in a linear, no-fork version of the chain.
#
-# Copyright (c) 2013-2014 The Bitcoin Core developers
+# Copyright (c) 2013-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 print_function
+try: # Python 3
+ import http.client as httplib
+except ImportError: # Python 2
+ import httplib
import json
-import struct
import re
import base64
-import httplib
import sys
+import os
+import os.path
settings = {}
+##### Switch endian-ness #####
+def hex_switchEndian(s):
+ """ Switches the endianness of a hex string (in pairs of hex chars) """
+ pairList = [s[i:i+2].encode() for i in range(0, len(s), 2)]
+ return b''.join(pairList[::-1]).decode()
+
class BitcoinRPC:
def __init__(self, host, port, username, password):
authpair = "%s:%s" % (username, password)
- self.authhdr = "Basic %s" % (base64.b64encode(authpair))
- self.conn = httplib.HTTPConnection(host, port, False, 30)
+ authpair = authpair.encode('utf-8')
+ self.authhdr = b"Basic " + base64.b64encode(authpair)
+ self.conn = httplib.HTTPConnection(host, port=port, timeout=30)
def execute(self, obj):
- self.conn.request('POST', '/', json.dumps(obj),
- { 'Authorization' : self.authhdr,
- 'Content-type' : 'application/json' })
+ try:
+ self.conn.request('POST', '/', json.dumps(obj),
+ { 'Authorization' : self.authhdr,
+ 'Content-type' : 'application/json' })
+ except ConnectionRefusedError:
+ print('RPC connection refused. Check RPC settings and the server status.',
+ file=sys.stderr)
+ return None
resp = self.conn.getresponse()
if resp is None:
print("JSON-RPC: no response", file=sys.stderr)
return None
- body = resp.read()
+ body = resp.read().decode('utf-8')
resp_obj = json.loads(body)
return resp_obj
@@ -64,16 +80,29 @@ def get_block_hashes(settings, max_blocks_per_call=10000):
batch.append(rpc.build_request(x, 'getblockhash', [height + x]))
reply = rpc.execute(batch)
+ if reply is None:
+ print('Cannot continue. Program will halt.')
+ return None
for x,resp_obj in enumerate(reply):
if rpc.response_is_error(resp_obj):
print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr)
exit(1)
assert(resp_obj['id'] == x) # assume replies are in-sequence
+ if settings['rev_hash_bytes'] == 'true':
+ resp_obj['result'] = hex_switchEndian(resp_obj['result'])
print(resp_obj['result'])
height += num_blocks
+def get_rpc_cookie():
+ # Open the cookie file
+ with open(os.path.join(os.path.expanduser(settings['datadir']), '.cookie'), 'r') as f:
+ combined = f.readline()
+ combined_split = combined.split(":")
+ settings['rpcuser'] = combined_split[0]
+ settings['rpcpassword'] = combined_split[1]
+
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: linearize-hashes.py CONFIG-FILE")
@@ -101,13 +130,28 @@ if __name__ == '__main__':
settings['min_height'] = 0
if 'max_height' not in settings:
settings['max_height'] = 313000
+ if 'rev_hash_bytes' not in settings:
+ settings['rev_hash_bytes'] = 'false'
+
+ use_userpass = True
+ use_datadir = False
if 'rpcuser' not in settings or 'rpcpassword' not in settings:
- print("Missing username and/or password in cfg file", file=stderr)
+ use_userpass = False
+ if 'datadir' in settings and not use_userpass:
+ use_datadir = True
+ if not use_userpass and not use_datadir:
+ print("Missing datadir or username and/or password in cfg file", file=stderr)
sys.exit(1)
settings['port'] = int(settings['port'])
settings['min_height'] = int(settings['min_height'])
settings['max_height'] = int(settings['max_height'])
- get_block_hashes(settings)
+ # Force hash byte format setting to be lowercase to make comparisons easier.
+ settings['rev_hash_bytes'] = settings['rev_hash_bytes'].lower()
+ # Get the rpc user and pass from the cookie if the datadir is set
+ if use_datadir:
+ get_rpc_cookie()
+
+ get_block_hashes(settings)
diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py
index 03e2325fc0..e6ecabace1 100755
--- a/contrib/macdeploy/custom_dsstore.py
+++ b/contrib/macdeploy/custom_dsstore.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Copyright (c) 2013-2015 The Bitcoin Core developers
+# Copyright (c) 2013-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
diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh
index 781fe315ed..91674a92e6 100755
--- a/contrib/macdeploy/detached-sig-apply.sh
+++ b/contrib/macdeploy/detached-sig-apply.sh
@@ -1,4 +1,8 @@
#!/bin/sh
+# Copyright (c) 2014-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.
+
set -e
UNSIGNED="$1"
diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh
index 89a2da32f7..7f017bb4f1 100755
--- a/contrib/macdeploy/detached-sig-create.sh
+++ b/contrib/macdeploy/detached-sig-create.sh
@@ -1,4 +1,8 @@
#!/bin/sh
+# Copyright (c) 2014-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.
+
set -e
ROOTDIR=dist
@@ -6,7 +10,7 @@ BUNDLE="${ROOTDIR}/Bitcoin-Qt.app"
CODESIGN=codesign
TEMPDIR=sign.temp
TEMPLIST=${TEMPDIR}/signatures.txt
-OUT=signature.tar.gz
+OUT=signature-osx.tar.gz
OUTROOT=osx
if [ ! -n "$1" ]; then
diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh
new file mode 100755
index 0000000000..ff9fbd58df
--- /dev/null
+++ b/contrib/macdeploy/extract-osx-sdk.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright (c) 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.
+
+set -e
+
+INPUTFILE="Xcode_7.3.1.dmg"
+HFSFILENAME="5.hfs"
+SDKDIR="Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk"
+
+7z x "${INPUTFILE}" "${HFSFILENAME}"
+SDKNAME="$(basename "${SDKDIR}")"
+SDKDIRINODE=$(ifind -n "${SDKDIR}" "${HFSFILENAME}")
+fls "${HFSFILENAME}" -rpF ${SDKDIRINODE} |
+ while read type inode filename; do
+ inode="${inode::-1}"
+ if [ "${filename:0:14}" = "usr/share/man/" ]; then
+ continue
+ fi
+ filename="${SDKNAME}/$filename"
+ echo "Extracting $filename ..."
+ mkdir -p "$(dirname "$filename")"
+ if [ "$type" = "l/l" ]; then
+ ln -s "$(icat "${HFSFILENAME}" $inode)" "$filename"
+ else
+ icat "${HFSFILENAME}" $inode >"$filename"
+ fi
+done
+echo "Building ${SDKNAME}.tar.gz ..."
+MTIME="$(istat "${HFSFILENAME}" "${SDKDIRINODE}" | perl -nle 'm/Content Modified:\s+(.*?)\s\(/ && print $1')"
+find "${SDKNAME}" | sort | tar --no-recursion --mtime="${MTIME}" --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > "${SDKNAME}.tar.gz"
+echo 'All done!'
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus
index f8201e72c6..23a568ad13 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -302,7 +302,6 @@ def copyFramework(framework, path, verbose):
if os.path.exists(fromContentsDir):
toContentsDir = os.path.join(path, framework.destinationVersionContentsDirectory)
shutil.copytree(fromContentsDir, toContentsDir, symlinks=True)
- contentslinkfrom = os.path.join(path, framework.destinationContentsDirectory)
if verbose >= 3:
print("Copied Contents:", fromContentsDir)
print(" to:", toContentsDir)
@@ -340,7 +339,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym
# install_name_tool the new id into the binary
changeInstallName(framework.installName, framework.deployedInstallName, binaryPath, verbose)
- # Copy farmework to app bundle.
+ # Copy framework to app bundle.
deployedBinaryPath = copyFramework(framework, bundlePath, verbose)
# Skip the rest if already was deployed.
if deployedBinaryPath is None:
@@ -492,7 +491,7 @@ ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, h
ap.add_argument("-sign", dest="sign", action="store_true", default=False, help="sign .app bundle with codesign tool")
ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used")
ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work")
-ap.add_argument("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's ressources; the language list must be separated with commas, not with whitespace")
+ap.add_argument("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's resources; the language list must be separated with commas, not with whitespace")
ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translation files")
ap.add_argument("-add-resources", nargs="+", metavar="path", default=[], help="list of additional files or folders to be copied into the bundle's resources; must be the last argument")
ap.add_argument("-volname", nargs=1, metavar="volname", default=[], help="custom volume name for dmg")
@@ -675,9 +674,8 @@ else:
if verbose >= 2:
print("+ Installing qt.conf +")
-f = open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb")
-f.write(qt_conf.encode())
-f.close()
+with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f:
+ f.write(qt_conf.encode())
# ------------------------------------------------
@@ -791,7 +789,7 @@ if config.dmg is not None:
except subprocess.CalledProcessError as e:
sys.exit(e.returncode)
- m = re.search("/Volumes/(.+$)", output)
+ m = re.search("/Volumes/(.+$)", output.decode())
disk_root = m.group(0)
disk_name = m.group(1)
@@ -852,7 +850,7 @@ if config.dmg is not None:
"items_positions" : "\n ".join(items_positions)
}
if "window_bounds" in fancy:
- params["window.bounds"] = ",".join([str(p) for p in fancy["window_bounds"]])
+ params["window_bounds"] = ",".join([str(p) for p in fancy["window_bounds"]])
if "icon_size" in fancy:
params["icon_size"] = str(fancy["icon_size"])
if bg_path is not None:
@@ -868,7 +866,7 @@ if config.dmg is not None:
print(s)
p = subprocess.Popen(['osascript', '-'], stdin=subprocess.PIPE)
- p.communicate(input=s)
+ p.communicate(input=s.encode('utf-8'))
if p.returncode:
print("Error running osascript.")
diff --git a/contrib/qos/README.md b/contrib/qos/README.md
index 5e0a975fc6..0ded87c58f 100644
--- a/contrib/qos/README.md
+++ b/contrib/qos/README.md
@@ -1,5 +1,5 @@
-### Qos ###
+### QoS (Quality of service) ###
-This is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Bitcoin network. It limits outbound TCP traffic with a source or destination port of 8333, but not if the destination IP is within a LAN (defined as 192.168.x.x).
+This is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Bitcoin network. It limits outbound TCP traffic with a source or destination port of 8333, but not if the destination IP is within a LAN.
This means one can have an always-on bitcoind instance running, and another local bitcoind/bitcoin-qt instance which connects to this node and receives blocks from it.
diff --git a/contrib/qos/tc.sh b/contrib/qos/tc.sh
index f620604212..0d1dd65b4f 100644
--- a/contrib/qos/tc.sh
+++ b/contrib/qos/tc.sh
@@ -1,11 +1,17 @@
+# 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.
+
#network interface on which to limit traffic
IF="eth0"
#limit of the network interface in question
LINKCEIL="1gbit"
#limit outbound Bitcoin protocol traffic to this rate
LIMIT="160kbit"
-#defines the address space for which you wish to disable rate limiting
-LOCALNET="192.168.0.0/16"
+#defines the IPv4 address space for which you wish to disable rate limiting
+LOCALNET_V4="192.168.0.0/16"
+#defines the IPv6 address space for which you wish to disable rate limiting
+LOCALNET_V6="fe80::/10"
#delete existing rules
tc qdisc del dev ${IF} root
@@ -24,6 +30,12 @@ tc class add dev ${IF} parent 1:1 classid 1:11 htb rate ${LIMIT} ceil ${LIMIT} p
tc filter add dev ${IF} parent 1: protocol ip prio 1 handle 1 fw classid 1:10
tc filter add dev ${IF} parent 1: protocol ip prio 2 handle 2 fw classid 1:11
+if [ ! -z "${LOCALNET_V6}" ] ; then
+ # v6 cannot have the same priority value as v4
+ tc filter add dev ${IF} parent 1: protocol ipv6 prio 3 handle 1 fw classid 1:10
+ tc filter add dev ${IF} parent 1: protocol ipv6 prio 4 handle 2 fw classid 1:11
+fi
+
#delete any existing rules
#disable for now
#ret=0
@@ -33,9 +45,15 @@ tc filter add dev ${IF} parent 1: protocol ip prio 2 handle 2 fw classid 1:11
#done
#limit outgoing traffic to and from port 8333. but not when dealing with a host on the local network
-# (defined by $LOCALNET)
-# --set-mark marks packages matching these criteria with the number "2"
-# these packages are filtered by the tc filter with "handle 2"
+# (defined by $LOCALNET_V4 and $LOCALNET_V6)
+# --set-mark marks packages matching these criteria with the number "2" (v4)
+# --set-mark marks packages matching these criteria with the number "4" (v6)
+# these packets are filtered by the tc filter with "handle 2"
# this filter sends the packages into the 1:11 class, and this class is limited to ${LIMIT}
-iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 8333 ! -d ${LOCALNET} -j MARK --set-mark 0x2
-iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 8333 ! -d ${LOCALNET} -j MARK --set-mark 0x2
+iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 8333 ! -d ${LOCALNET_V4} -j MARK --set-mark 0x2
+iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 8333 ! -d ${LOCALNET_V4} -j MARK --set-mark 0x2
+
+if [ ! -z "${LOCALNET_V6}" ] ; then
+ ip6tables -t mangle -A OUTPUT -p tcp -m tcp --dport 8333 ! -d ${LOCALNET_V6} -j MARK --set-mark 0x4
+ ip6tables -t mangle -A OUTPUT -p tcp -m tcp --sport 8333 ! -d ${LOCALNET_V6} -j MARK --set-mark 0x4
+fi
diff --git a/contrib/qt_translations.py b/contrib/qt_translations.py
deleted file mode 100755
index fd8a8b7129..0000000000
--- a/contrib/qt_translations.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-
-# Helpful little script that spits out a comma-separated list of
-# language codes for Qt icons that should be included
-# in binary bitcoin distributions
-
-import glob
-import os
-import re
-import sys
-
-if len(sys.argv) != 3:
- sys.exit("Usage: %s $QTDIR/translations $BITCOINDIR/src/qt/locale"%sys.argv[0])
-
-d1 = sys.argv[1]
-d2 = sys.argv[2]
-
-l1 = set([ re.search(r'qt_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d1, 'qt_*.qm')) ])
-l2 = set([ re.search(r'bitcoin_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d2, 'bitcoin_*.qm')) ])
-
-print ",".join(sorted(l1.intersection(l2)))
-
diff --git a/contrib/rpm/README.md b/contrib/rpm/README.md
index aecb3ba84f..e1fd0b317b 100644
--- a/contrib/rpm/README.md
+++ b/contrib/rpm/README.md
@@ -31,7 +31,7 @@ through `Source23` are used.
Sources 30-39 should be reserved for SELinux related files. Currently only
`Source30` through `Source32` are used. Until those files are in a tagged
release, the full URL specified in the RPM spec file will not work. You can get
-them from the git ropository where you retrieved this file.
+them from the git repository where you retrieved this file.
Sources 100+ are for files that are not source tarballs and are not maintained
in the bitcoin git repository. At present only an SVG version of the Bitcoin
diff --git a/contrib/rpm/bitcoin.spec b/contrib/rpm/bitcoin.spec
index 38ae038180..cc54fcaf3d 100644
--- a/contrib/rpm/bitcoin.spec
+++ b/contrib/rpm/bitcoin.spec
@@ -27,10 +27,9 @@ Source1: http://download.oracle.com/berkeley-db/db-%{bdbv}.NC.tar.gz
Source10: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/examples/bitcoin.conf
#man pages
-Source20: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoind.1
-Source21: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin-cli.1
-Source22: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin-qt.1
-Source23: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin.conf.5
+Source20: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/doc/man/bitcoind.1
+Source21: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/doc/man/bitcoin-cli.1
+Source22: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/doc/man/bitcoin-qt.1
#selinux
Source30: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/rpm/bitcoin.te
@@ -306,17 +305,14 @@ install -p %{SOURCE21} %{buildroot}%{_mandir}/man1/bitcoin-cli.1
%if %{_buildqt}
install -p %{SOURCE22} %{buildroot}%{_mandir}/man1/bitcoin-qt.1
%endif
-install -D -p %{SOURCE23} %{buildroot}%{_mandir}/man5/bitcoin.conf.5
# nuke these, we do extensive testing of binaries in %%check before packaging
rm -f %{buildroot}%{_bindir}/test_*
%check
make check
-pushd src
-srcdir=. test/bitcoin-util-test.py
-popd
-qa/pull-tester/rpc-tests.py -extended
+srcdir=src test/bitcoin-util-test.py
+test/functional/test_runner.py --extended
%post libs -p /sbin/ldconfig
@@ -415,7 +411,6 @@ rm -rf %{buildroot}
%config(noreplace) %attr(0600,root,root) %{_sysconfdir}/sysconfig/bitcoin
%attr(0644,root,root) %{_datadir}/selinux/*/*.pp
%attr(0644,root,root) %{_mandir}/man1/bitcoind.1*
-%attr(0644,root,root) %{_mandir}/man5/bitcoin.conf.5*
%files utils
%defattr(-,root,root,-)
@@ -425,7 +420,6 @@ rm -rf %{buildroot}
%attr(0755,root,root) %{_bindir}/bitcoin-tx
%attr(0755,root,root) %{_bindir}/bench_bitcoin
%attr(0644,root,root) %{_mandir}/man1/bitcoin-cli.1*
-%attr(0644,root,root) %{_mandir}/man5/bitcoin.conf.5*
diff --git a/contrib/seeds/README.md b/contrib/seeds/README.md
index c595f83eb9..afe902fd7f 100644
--- a/contrib/seeds/README.md
+++ b/contrib/seeds/README.md
@@ -1,11 +1,19 @@
-### Seeds ###
+# Seeds
Utility to generate the seeds.txt list that is compiled into the client
(see [src/chainparamsseeds.h](/src/chainparamsseeds.h) and other utilities in [contrib/seeds](/contrib/seeds)).
+Be sure to update `PATTERN_AGENT` in `makeseeds.py` to include the current version,
+and remove old versions as necessary.
+
The seeds compiled into the release are created from sipa's DNS seed data, like this:
curl -s http://bitcoin.sipa.be/seeds.txt > seeds_main.txt
- python makeseeds.py < seeds_main.txt > nodes_main.txt
- python generate-seeds.py . > ../../src/chainparamsseeds.h
+ python3 makeseeds.py < seeds_main.txt > nodes_main.txt
+ python3 generate-seeds.py . > ../../src/chainparamsseeds.h
+
+## Dependencies
+
+Ubuntu:
+ sudo apt-get install python3-dnspython
diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py
index a3d0352187..b0ac92ae03 100755
--- a/contrib/seeds/generate-seeds.py
+++ b/contrib/seeds/generate-seeds.py
@@ -1,5 +1,5 @@
-#!/usr/bin/python
-# Copyright (c) 2014 Wladimir J. van der Laan
+#!/usr/bin/env python3
+# Copyright (c) 2014-2017 Wladimir J. van der Laan
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
@@ -31,7 +31,7 @@ The output will be two data structures with the peers in binary format:
These should be pasted into `src/chainparamsseeds.h`.
'''
-from __future__ import print_function, division
+
from base64 import b32decode
from binascii import a2b_hex
import sys, os
diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py
index 4072405ef5..34f0f57671 100755
--- a/contrib/seeds/makeseeds.py
+++ b/contrib/seeds/makeseeds.py
@@ -1,4 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+# Copyright (c) 2013-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.
#
# Generate seeds.txt from Pieter's DNS seeder
#
@@ -11,13 +14,13 @@ MIN_BLOCKS = 337600
# These are hosts that have been observed to be behaving strangely (e.g.
# aggressively connecting to every node).
-SUSPICIOUS_HOSTS = set([
+SUSPICIOUS_HOSTS = {
"130.211.129.106", "178.63.107.226",
"83.81.130.26", "88.198.17.7", "148.251.238.178", "176.9.46.6",
"54.173.72.127", "54.174.10.182", "54.183.64.54", "54.194.231.211",
"54.66.214.167", "54.66.220.137", "54.67.33.14", "54.77.251.214",
"54.94.195.96", "54.94.200.247"
-])
+}
import re
import sys
@@ -27,7 +30,7 @@ import collections
PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$")
PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$")
PATTERN_ONION = re.compile(r"^([abcdefghijklmnopqrstuvwxyz234567]{16}\.onion):(\d+)$")
-PATTERN_AGENT = re.compile(r"^(\/Satoshi:0\.8\.6\/|\/Satoshi:0\.9\.(2|3|4|5)\/|\/Satoshi:0\.10\.\d{1,2}\/|\/Satoshi:0\.11\.\d{1,2}\/)$")
+PATTERN_AGENT = re.compile(r"^(/Satoshi:0.12.(0|1|99)/|/Satoshi:0.13.(0|1|2|99)/)$")
def parseline(line):
sline = line.split()
@@ -101,7 +104,7 @@ def filtermultiport(ips):
hist = collections.defaultdict(list)
for ip in ips:
hist[ip['sortkey']].append(ip)
- return [value[0] for (key,value) in hist.items() if len(value)==1]
+ return [value[0] for (key,value) in list(hist.items()) if len(value)==1]
# Based on Greg Maxwell's seed_filter.py
def filterbyasn(ips, max_per_asn, max_total):
@@ -161,9 +164,9 @@ def main():
for ip in ips:
if ip['net'] == 'ipv6':
- print '[%s]:%i' % (ip['ip'], ip['port'])
+ print('[%s]:%i' % (ip['ip'], ip['port']))
else:
- print '%s:%i' % (ip['ip'], ip['port'])
+ print('%s:%i' % (ip['ip'], ip['port']))
if __name__ == '__main__':
main()
diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt
index f1854b27f9..0451771dae 100644
--- a/contrib/seeds/nodes_main.txt
+++ b/contrib/seeds/nodes_main.txt
@@ -1,937 +1,1168 @@
-5.2.145.201:8333
-5.22.142.214:8333
-5.53.172.197:8333
-5.189.161.164:8333
-5.230.140.166:8333
-5.231.3.130:8333
-5.255.80.103:8333
-14.202.230.49:8333
-18.85.11.130:8333
-23.91.97.25:8333
-23.94.100.122:8333
-23.95.99.132:8333
-24.115.8.206:8333
-24.127.128.191:8333
-24.154.178.25:8333
-24.207.103.43:8333
-24.207.104.105:8333
-24.210.230.150:8333
-24.224.18.84:8333
-24.246.168.106:8333
-27.254.64.47:8333
-31.6.71.123:8333
-31.6.71.124:8333
-31.14.134.13:8333
-31.30.36.220:8333
-31.164.6.104:8333
+2.7.8.12:8333
+2.228.70.198:8333
+5.39.64.7:8333
+5.45.80.34:38333
+5.51.160.38:8333
+5.61.33.33:8333
+5.61.37.12:8333
+5.95.80.47:8333
+5.102.164.173:8333
+5.175.71.130:8333
+5.189.165.22:8333
+5.199.130.228:8333
+5.228.100.222:8333
+5.255.64.231:8333
+13.93.6.133:8333
+18.85.34.10:8333
+18.241.0.63:8333
+23.28.128.65:8333
+23.248.113.52:8333
+23.253.151.73:8333
+24.4.96.121:8333
+24.69.65.191:8333
+24.87.8.43:8333
+24.150.224.110:8333
+24.227.69.146:8333
+27.0.235.33:8333
31.170.106.203:8333
-31.185.134.201:8333
-31.204.128.99:8333
-31.204.128.219:8333
-37.1.219.88:8333
-37.97.132.109:8333
-37.120.160.55:8333
+31.184.197.96:8333
+31.214.240.56:8333
+37.1.202.134:8333
+37.18.74.232:8333
+37.34.48.17:8333
+37.48.64.140:8333
+37.97.141.116:8333
+37.120.164.16:8333
37.120.169.123:8333
-37.139.32.46:8333
-37.221.163.218:8333
-38.130.192.72:8333
-41.75.96.80:8333
-45.3.0.49:8333
-45.33.72.185:8333
-45.33.96.129:8333
-45.56.4.63:8333
-45.79.0.127:8333
-45.79.80.102:8333
-45.79.97.30:8333
-45.79.132.219:8333
-46.21.97.135:8333
-46.28.205.67:8333
-46.28.206.188:8333
-46.29.20.209:8333
-46.50.234.179:8333
-46.101.160.168:8333
-46.166.161.35:8333
-46.166.161.103:8333
-46.182.132.100:8333
-46.218.227.92:8333
-46.226.109.20:8333
-46.227.66.132:8333
-46.227.66.138:8333
-46.229.165.154:8333
-46.229.165.155:8333
+37.143.9.128:8333
+37.153.172.227:8333
+37.193.227.16:8333
+37.205.8.78:8333
+37.220.0.114:8333
+37.232.218.199:8333
+38.140.161.53:8333
+40.87.70.120:8333
+41.162.163.93:8333
+42.2.198.48:8333
+45.20.67.1:8333
+45.55.197.77:8333
+45.56.97.63:8333
+45.58.38.162:8333
+45.63.1.33:8333
+45.79.2.70:8333
+46.16.240.98:8333
+46.19.137.74:8333
+46.28.206.146:8333
+46.32.252.197:8333
+46.59.13.59:8333
+46.59.39.195:8333
+46.148.16.210:8333
+46.160.195.121:8333
+46.166.142.21:8333
+46.166.160.29:8330
+46.188.44.20:8333
46.229.238.187:8333
-46.234.104.48:8333
-46.239.107.74:8333
-46.244.0.138:8333
-46.254.72.195:8333
-50.5.13.44:8333
-50.7.37.114:8333
-50.30.37.103:8333
-50.39.105.60:8333
-50.106.40.231:8333
-52.29.0.37:8333
-52.76.192.246:8333
-54.152.192.179:8333
-54.169.64.174:8333
-54.175.160.22:8333
-54.199.128.0:8333
-58.96.171.129:8333
-58.161.238.57:8333
-60.251.195.221:8333
-61.35.225.19:8333
+46.231.16.149:8333
+47.88.100.130:8333
+47.89.192.134:8333
+47.185.194.160:8333
+47.189.129.218:8333
+49.65.2.140:8333
+50.3.72.129:8333
+50.31.99.225:8333
+51.175.33.95:8333
+52.1.165.219:8333
+52.10.170.186:8333
+52.51.128.216:8333
+54.197.130.244:8333
+58.59.2.22:8333
+58.84.6.81:8333
+59.125.8.143:8333
+59.167.130.139:8333
+61.47.2.20:8333
62.43.130.178:8333
-62.65.39.12:8333
+62.76.96.6:8333
62.107.200.30:8333
+62.133.15.58:8333
62.133.194.2:8333
-62.181.238.186:8333
-62.183.22.50:8333
-62.210.85.120:8333
-62.210.162.89:8333
+62.133.194.156:8333
+62.138.1.95:8333
+62.216.238.3:8333
62.238.34.125:8333
-64.25.171.73:8333
-64.27.166.30:8333
-64.53.137.101:8333
-64.71.72.44:8333
+63.137.40.207:8333
+63.231.96.109:8333
+64.78.240.150:8333
64.83.225.146:8333
-64.121.3.163:8333
-64.203.102.86:8333
-65.94.131.59:8333
-65.188.136.233:8333
-66.11.162.218:8333
-66.23.228.133:8333
-66.90.137.89:8333
-66.114.33.49:8333
-66.150.105.77:8333
+64.137.236.68:8833
+64.156.193.120:8333
+66.79.160.82:8333
+66.91.230.231:8333
+66.135.128.121:8333
66.172.10.4:8333
66.194.38.250:8333
66.194.38.253:8333
-66.194.38.254:8333
-66.231.97.172:8333
+66.215.34.26:8333
66.240.237.155:8333
-67.159.13.34:8333
-67.205.74.206:8333
+67.205.96.108:8333
+67.205.128.5:8333
+67.219.233.140:8333
67.221.193.55:8333
-67.227.72.17:8333
-68.65.120.53:8333
-68.65.205.226:9000
-68.144.4.34:8333
-69.39.49.199:8333
+68.100.196.118:8333
+68.132.193.222:8333
+68.168.118.234:8333
+69.11.97.43:8333
+69.30.229.10:8333
69.50.171.205:8333
-69.65.41.21:8333
-69.113.98.61:8333
-69.119.97.39:8333
-69.146.70.124:8333
-69.193.71.2:8333
-70.46.10.237:8333
-70.80.200.187:8333
-70.185.97.117:8333
-71.254.160.25:8333
-72.28.203.5:8333
-72.52.130.110:8333
-72.83.194.122:8333
-72.128.32.167:8333
-72.179.136.80:8333
-72.235.38.70:8333
-74.50.44.193:8333
-74.72.60.83:8333
-74.80.234.116:8333
-74.207.233.193:8333
-75.112.233.128:8333
-75.118.166.197:8333
-75.140.0.241:8333
-75.159.240.66:8333
-75.174.5.26:8333
-76.72.160.252:8333
-76.72.160.254:8333
-76.74.170.112:8333
-76.79.201.54:8333
-76.175.166.164:8333
-76.179.105.27:8333
-77.68.37.200:8333
-77.234.49.196:8333
-77.247.229.93:8333
-78.24.72.78:8333
-78.47.32.147:8333
-78.84.100.95:8333
-78.121.69.23:8333
-78.129.167.5:8333
-78.193.96.155:8333
-79.19.37.179:8333
+69.125.193.145:8333
+69.162.139.125:8333
+70.35.98.39:8333
+70.112.32.29:8333
+71.126.181.146:8333
+72.180.32.105:8333
+73.226.64.145:8333
+74.83.140.242:8333
+74.84.128.158:9333
+74.122.237.124:8333
+74.215.133.145:8333
+75.76.101.169:8333
+75.85.13.8:8333
+75.86.168.13:8333
+75.170.97.25:8333
+75.177.137.134:8333
+76.76.227.136:8333
+77.53.136.6:8333
+77.110.11.52:8333
+78.25.32.206:8333
+78.34.8.120:8333
+78.46.32.99:8333
+78.56.9.214:8333
+78.56.229.177:8333
+78.129.237.245:8333
+78.196.172.45:8333
79.132.230.144:8333
-79.133.43.63:8333
-79.134.201.66:8333
79.169.35.235:8333
-80.57.227.14:8333
+79.172.194.219:8333
80.64.65.87:8333
-80.86.92.70:8333
-80.100.203.151:8333
-80.101.32.121:8333
-80.161.178.73:8333
-80.240.129.170:8333
-81.7.11.50:8333
-81.7.11.55:8333
-81.17.17.40:9333
-81.30.39.83:8333
-81.90.36.7:9444
-81.136.224.77:8333
-81.162.231.211:8333
-81.184.0.143:8333
-81.198.128.86:8333
+80.89.137.115:8333
+80.93.36.173:8333
+80.101.167.100:8333
+80.114.34.158:8333
+80.127.136.50:8333
+80.188.139.82:8333
+80.222.39.77:8333
+80.223.105.69:8333
+80.229.151.187:8333
+80.240.129.221:8333
+81.7.10.238:8333
+81.7.13.84:8333
+81.27.96.92:8333
+81.35.143.98:8333
+81.82.201.5:8333
+81.83.96.5:8333
+81.169.227.36:8333
+81.171.2.119:8333
+81.171.38.130:8333
+81.175.255.118:8333
+81.207.8.49:8333
+81.228.194.187:8333
+82.9.1.77:8333
82.11.33.229:8333
-82.79.128.134:8333
-82.118.233.111:8333
-82.135.139.30:8333
+82.102.13.117:8333
+82.116.203.240:8333
+82.130.103.16:8333
+82.136.65.227:8333
+82.158.227.238:8333
+82.197.212.25:8333
82.199.102.10:8333
-82.221.106.17:8333
-82.221.108.21:8333
+82.200.204.41:8333
+82.200.204.119:8333
+82.221.105.223:8333
82.221.108.27:8333
-83.137.41.3:8333
-83.142.197.168:8333
+82.221.111.136:8333
+82.221.139.97:8333
+83.137.41.10:8333
83.143.130.19:8333
83.150.9.196:8333
-83.183.17.191:8333
-83.227.173.83:8333
-83.230.5.15:8333
-83.233.105.151:443
-83.246.75.8:8333
-83.250.133.158:8333
-83.255.66.118:8334
-84.24.69.59:8333
+83.169.2.43:8333
+83.217.203.130:8333
+83.249.88.52:8333
+84.26.162.92:8333
84.42.193.6:8333
-84.45.98.87:8333
-84.54.128.11:8333
-84.212.200.24:8333
-84.215.198.109:8333
-84.230.4.177:8333
-85.95.228.83:8333
-85.95.228.123:8333
-85.114.128.134:8333
-85.214.66.168:8333
-85.214.147.162:8333
-85.243.168.4:8333
-86.1.0.18:8333
-87.79.77.106:8333
-87.91.156.110:8333
-87.236.196.222:8333
-88.85.75.152:8333
-88.87.1.230:8333
-88.87.92.102:8333
-88.89.69.202:8333
-88.97.72.229:8333
-88.164.117.99:8333
-88.198.32.131:8333
+84.134.194.115:8333
+84.201.32.115:8333
+84.212.232.71:8333
+84.238.140.176:8333
+85.10.104.34:8333
+85.21.144.226:8333
+85.25.194.12:8333
+85.144.79.190:8333
+85.145.228.192:8333
+85.194.238.130:8333
+85.228.201.80:8333
+85.229.228.174:8333
+85.236.233.87:8333
+86.80.204.185:8333
+86.105.227.190:8333
+86.135.39.40:8333
+87.106.139.127:8333
+87.120.8.5:8333
+87.120.37.230:8333
+87.239.101.102:8333
+87.243.197.82:8333
+88.112.112.173:8333
+88.150.192.17:8333
+88.185.155.134:8333
+88.202.202.221:8333
88.202.230.87:8333
-88.214.193.154:8343
-88.214.194.226:8343
-89.10.155.88:8333
-89.46.101.44:8333
-89.163.224.212:8333
-89.174.248.20:8333
-89.202.231.198:8333
-89.212.75.6:8333
+88.208.39.182:8333
+89.34.99.41:8333
+89.163.224.187:8333
+89.169.233.150:8333
+89.184.65.85:8333
+89.212.91.219:8333
+89.249.178.36:8333
90.149.38.172:8333
-90.169.106.139:8333
-91.64.101.150:8333
-91.65.196.179:8333
-91.121.80.17:8333
-91.126.77.77:8333
-91.145.76.156:8333
-91.152.150.35:8333
-91.192.137.17:8333
-91.196.170.110:8333
+91.65.97.157:8333
+91.107.64.143:8333
+91.114.35.107:8333
+91.135.0.187:8333
+91.145.110.95:8333
+91.157.38.151:8333
91.197.44.133:8333
-91.207.68.144:8333
-91.210.105.28:8333
-91.211.102.101:8333
-91.211.106.34:8333
-91.214.200.205:8333
-91.220.43.146:8333
-91.222.71.89:8333
-91.224.140.242:8333
-91.229.76.14:8333
+91.205.176.54:8333
+91.206.203.10:8333
+91.206.203.18:8333
+91.215.35.130:8333
+91.219.239.159:8333
+91.223.133.2:8333
+91.223.133.40:8333
+91.226.10.90:8333
+91.240.141.169:8333
92.27.7.209:8333
-92.51.167.88:8333
-92.247.229.163:8333
-93.84.114.106:8333
-93.113.36.172:8333
+92.89.67.207:8333
+92.221.201.138:8333
+93.95.187.122:8333
+93.103.73.187:8333
+93.123.80.47:8333
93.188.224.253:8333
-94.75.239.69:8333
-94.190.227.112:8333
-94.214.2.74:8333
-94.224.162.65:8333
-94.236.198.253:8333
+93.190.69.242:8333
+94.19.12.244:8333
+94.156.128.116:8333
+94.177.171.73:8333
+94.181.44.104:8333
+94.237.26.173:8333
94.242.229.158:8333
-95.84.138.99:8333
-95.95.168.87:8333
+94.255.128.98:8333
+95.79.35.50:8333
+95.91.41.39:8333
95.110.234.93:8333
-95.130.9.200:8333
-95.165.168.168:8333
-95.170.235.254:8333
-95.211.130.154:8333
-96.46.68.104:8333
-96.127.202.148:8333
-97.76.171.35:8333
-98.160.160.67:8333
-99.126.197.187:8333
-99.198.173.1:8333
-101.100.174.138:8333
-101.164.201.208:8333
-103.224.165.48:8333
-104.128.225.223:8333
+95.128.48.209:8333
+95.183.48.71:8333
+96.23.67.85:8333
+97.64.177.10:8333
+97.104.201.95:8333
+98.29.197.149:8333
+98.169.2.107:8333
+99.232.48.72:8333
+101.100.141.55:8333
+103.7.32.40:8333
+103.53.225.69:8333
+103.249.106.74:8333
+104.128.224.13:8333
104.128.228.252:8333
-104.131.192.94:8333
-104.155.45.201:8334
-104.194.28.195:8663
-104.211.1.27:8333
-104.221.38.177:8333
-104.236.9.79:8333
-104.236.129.178:8333
-104.236.186.249:8333
-104.236.194.15:8333
-104.238.128.214:8333
+104.155.1.158:8333
+104.168.128.50:8333
+104.199.160.228:8333
+104.204.109.11:8333
+104.219.251.118:8333
+104.223.3.129:8333
+104.223.3.219:8333
104.238.130.182:8333
-106.38.234.84:8333
-106.185.36.204:8333
-106.185.38.67:8333
-107.6.4.145:8333
-107.150.2.6:8333
-107.150.40.234:8333
-107.170.13.184:8333
-107.181.250.216:8333
-107.191.101.111:8333
-107.191.106.115:8333
+104.245.99.227:8333
+106.38.234.89:8333
+106.104.134.218:8333
+107.136.6.71:8333
+107.150.45.210:8333
+107.151.144.103:8333
+107.170.44.99:8333
+107.181.137.133:8333
+107.191.102.13:8333
+108.58.252.82:8333
+108.59.9.167:8333
108.59.12.163:8333
-108.161.129.247:8333
-109.193.160.140:8333
-109.197.13.54:8333
-109.230.7.248:8333
-109.234.106.191:8333
-109.236.137.80:8333
-109.251.161.121:8333
-112.65.231.226:8333
-115.70.166.57:8333
-115.159.42.80:8333
-117.18.73.34:8333
-118.67.201.40:8333
-118.100.86.246:8333
-118.110.104.152:8333
-119.224.64.141:8333
+108.162.106.215:8333
+108.168.133.164:8333
+108.173.202.101:8333
+108.180.110.190:8333
+109.29.75.40:8333
+109.120.194.136:8333
+109.230.230.88:8333
+109.235.67.115:8333
+109.235.69.120:8333
+109.236.90.199:8333
+109.255.0.107:8333
+110.10.130.12:8333
+110.10.176.94:8333
+110.132.172.251:8333
+111.90.158.17:8333
+115.66.205.171:8333
+116.31.123.139:8333
+118.192.48.46:8333
+118.193.164.98:8333
+119.29.156.231:8333
+119.63.44.133:19980
+119.81.99.27:8333
+119.106.12.169:8333
+119.147.137.155:19980
+119.185.1.182:8333
120.55.193.136:8333
-122.106.169.178:8333
-123.203.174.15:8333
-123.255.232.94:8333
-124.148.165.165:8333
-124.232.141.31:8333
-128.30.92.69:8333
-128.39.141.182:8333
-128.84.167.20:8333
-128.111.73.10:8333
-128.127.38.195:8333
+121.254.173.23:8333
+121.254.173.40:8333
+123.56.129.45:8333
+123.203.163.128:8333
+123.206.32.198:8333
+124.189.160.221:8333
+124.189.192.232:8333
128.140.224.162:8333
-128.199.101.104:8333
-128.233.224.35:8333
-128.253.3.193:20020
-130.180.228.138:8333
-130.185.144.213:8333
-130.255.73.207:8333
-133.218.233.11:8333
-134.249.128.23:8333
-136.159.234.234:8333
-137.116.160.176:8333
-139.162.2.145:8333
-139.162.23.117:8333
-141.134.69.253:8333
-141.255.162.215:8333
-144.122.163.187:8333
-145.131.3.54:8333
-145.255.4.94:8333
-146.0.32.101:8337
-147.83.72.91:8333
-148.103.28.68:8333
-149.5.32.102:8333
-149.210.164.195:8333
-150.101.163.241:8333
-151.236.11.189:8333
-152.3.136.56:8333
-154.20.208.25:8333
-158.181.104.149:8333
-159.253.96.226:8333
-160.36.130.180:8333
+128.199.68.205:8333
+130.234.207.115:8333
+131.113.41.123:8333
+131.114.72.104:8333
+132.204.108.155:8333
+134.119.13.230:8333
+134.213.133.206:8333
+134.213.133.207:8333
+135.23.5.3:8333
+137.74.0.66:8333
+138.68.1.45:8333
+138.68.2.194:8333
+138.68.64.19:8333
+138.68.64.28:8333
+139.59.42.248:8333
+139.220.240.153:8333
+140.112.107.118:8333
+140.186.224.112:8333
+141.52.64.141:8333
+142.68.237.107:8333
+142.217.12.106:8333
+146.60.204.92:8333
+146.185.161.209:8333
+148.103.7.119:8333
+149.210.133.244:8333
+150.229.0.143:8333
+151.231.238.25:8333
+151.248.160.227:8333
+153.230.228.15:8333
+155.133.43.249:8333
+158.58.238.145:8333
+158.109.79.13:34821
+159.203.70.208:8333
+160.16.206.31:8333
162.209.1.233:8333
162.209.4.125:8333
-162.209.106.123:8333
-162.210.198.184:8333
-162.248.99.164:53011
+162.216.192.231:8333
+162.243.100.111:8333
+162.246.11.194:8333
162.248.102.117:8333
-162.251.108.53:8333
-163.44.2.48:8333
-163.158.36.17:8333
-166.230.71.67:8333
-167.160.36.62:8333
-167.160.169.92:8333
-168.93.129.220:8333
-169.55.99.84:8333
-169.228.66.43:8333
-172.9.169.242:8333
-173.32.11.194:8333
-173.230.228.136:8333
-173.246.107.34:8333
-173.254.235.34:8333
-174.0.128.222:8333
-174.25.130.148:8333
-174.50.64.101:8333
-175.140.232.141:8333
-176.36.37.62:8333
-176.46.9.96:8333
-176.124.110.27:8333
-177.39.16.102:8333
-178.17.173.2:8333
-178.62.5.248:8333
-178.62.70.16:8333
+162.252.46.83:8333
+163.172.33.78:8333
+163.172.194.30:8333
+169.229.198.106:8333
+170.75.195.168:8333
+172.103.205.197:8333
+172.245.225.126:8333
+173.179.37.8:8333
+173.208.203.74:8333
+173.252.46.16:8333
+174.117.141.124:8333
+175.126.38.158:8333
+175.126.38.177:8333
+175.139.106.119:8333
+175.140.232.66:8333
+176.9.117.100:8333
+176.36.33.121:8333
+176.36.99.222:8333
+176.56.227.36:8333
+176.100.100.206:8333
+176.106.144.183:8333
+176.123.7.148:8333
+176.126.167.10:8333
+176.223.201.198:8333
+178.62.68.62:8333
+178.62.102.56:8333
178.62.203.185:8333
-178.79.160.118:8333
-178.169.206.244:8333
-178.193.234.62:8333
-178.199.96.108:8333
-178.254.18.96:8333
+178.124.197.101:8333
+178.170.138.202:8333
+178.175.129.18:8333
+178.188.47.62:8333
+178.199.240.22:8333
+178.218.209.162:8333
+178.237.35.34:8333
+178.238.224.242:8333
+178.254.34.144:8333
178.254.34.161:8333
-178.255.41.123:8333
-180.210.34.58:9801
-182.92.226.212:8333
-182.171.246.142:8333
-184.23.8.9:8333
-184.58.162.35:8333
-184.154.9.170:8333
-185.8.238.165:8333
+179.43.183.2:8333
+180.200.128.58:8333
+182.93.34.130:8333
+185.8.238.197:8333
+185.11.139.172:8333
185.24.97.11:8333
-185.31.137.139:8333
-185.38.44.64:8333
-185.53.128.180:8333
-185.53.129.244:8333
-185.77.129.119:8333
-185.77.129.156:8333
-185.82.203.92:8333
-188.20.97.18:8333
-188.126.8.14:8333
-188.138.33.239:8333
-188.155.136.70:8333
+185.24.233.100:8333
+185.25.48.71:8333
+185.25.48.114:8333
+185.28.76.179:8333
+185.70.105.152:8339
+185.77.128.69:8333
+185.77.128.241:8333
+185.86.79.87:8333
+185.89.102.2:3333
+185.89.102.53:3333
+185.109.144.155:8333
+185.117.75.50:8333
+185.121.173.223:8333
+185.128.41.157:8333
+185.130.226.106:8333
+185.145.130.76:8333
+188.63.192.104:8333
+188.113.164.231:8333
188.166.229.112:8333
-188.182.108.129:8333
-188.226.225.174:8010
-188.242.171.8:8333
-188.243.4.139:8333
-190.10.9.234:8333
-190.10.10.147:8333
+188.214.128.77:8333
+190.10.8.211:8333
190.81.160.184:8333
-190.85.201.37:8333
-192.34.227.230:8333
-192.77.189.200:8333
-192.124.224.7:8333
-192.146.137.1:8333
-192.203.228.71:8333
-192.206.202.20:8333
-193.0.109.3:8333
-193.41.229.130:8333
-193.41.229.156:8333
+190.111.231.19:8333
+192.131.44.93:8333
+192.206.202.6:8333
+192.227.245.133:8333
+192.241.74.123:8333
+192.241.74.126:8333
+192.254.71.222:8333
+193.10.64.85:8333
+193.46.80.101:8333
193.49.43.219:8333
-193.147.71.120:8333
-193.179.65.233:8333
+193.93.79.215:8333
193.183.99.46:8333
-193.192.37.135:8333
193.234.224.195:8333
-194.58.108.213:8333
-194.187.96.2:8333
-194.255.31.59:8333
-195.36.6.101:8333
-195.58.238.243:8333
-195.197.175.190:8333
-195.239.1.66:8333
-198.48.196.230:8333
-198.50.192.160:8333
-198.57.210.27:8333
-198.84.195.179:8333
-198.167.140.8:8333
+193.239.80.155:8333
+194.63.140.208:8333
+194.87.1.232:8333
+194.187.227.18:8333
+194.247.12.136:8333
+195.91.176.86:8333
+196.28.98.20:8333
+198.44.249.35:8333
+198.84.172.252:8333
198.204.224.106:8333
-199.127.226.245:8333
-199.201.110.8:8333
-199.233.234.90:8333
+198.211.97.46:8333
+199.66.64.198:8333
+199.101.100.58:8333
+199.101.100.59:8333
+199.127.224.50:8333
+200.46.241.71:8333
200.116.98.185:8333
-202.60.70.18:8333
-203.151.140.14:8333
-204.112.203.52:8333
+203.9.225.13:8333
+203.177.142.37:8333
205.200.247.149:8333
-207.226.141.253:8333
-207.255.42.202:8333
-208.53.164.19:8333
-208.66.68.127:8333
-208.66.68.130:8333
-208.71.171.232:8341
-208.76.200.200:8333
-208.82.98.189:8333
-208.85.193.31:8333
-208.111.48.41:8333
-208.111.48.45:8333
-209.34.232.72:8333
-209.81.9.223:8333
-209.90.224.2:8333
+205.209.131.150:13838
+206.53.64.74:8333
+206.72.192.69:8333
+206.123.112.180:8333
+208.66.208.153:8333
+208.68.174.76:8333
+208.107.97.242:8333
+208.111.48.132:8333
+208.118.235.190:8333
+209.6.205.126:8333
+209.40.96.121:8333
+209.58.130.137:8333
+209.73.142.226:8333
209.90.224.4:8333
-209.126.98.174:8333
-209.136.72.69:8333
-209.195.4.74:8333
-209.197.13.62:8333
-211.72.227.8:8333
-212.51.144.42:8333
-212.71.233.127:8333
-212.126.14.122:8333
-212.159.44.50:8333
-213.5.36.58:8333
-213.57.33.10:8333
-213.66.205.194:8333
-213.136.73.125:8333
-213.155.3.216:8333
-213.155.7.24:8333
-213.167.17.6:8333
-213.223.138.13:8333
-216.15.78.182:8333
-216.38.129.164:8333
-216.48.168.8:8333
-216.169.141.169:8333
-216.245.206.181:8333
-216.249.204.161:8333
-216.250.138.230:8333
+209.126.69.243:8333
+209.126.108.91:8333
+209.195.4.18:8333
+209.250.6.190:8333
+210.54.37.225:8333
+210.223.3.44:8333
+211.149.234.109:8333
+212.51.140.183:8333
+212.90.179.206:8333
+212.93.226.90:8333
+212.110.171.118:8333
+212.202.132.17:8333
+213.91.205.134:8333
+213.165.68.218:8333
+213.196.200.213:8333
+216.59.4.212:8333
+216.74.32.109:8333
+216.158.225.70:8333
+216.164.138.13:8333
+216.167.236.247:8333
+216.197.79.74:8333
217.11.225.189:8333
-217.12.34.158:8333
-217.12.202.33:8333
-217.20.171.43:8333
-217.23.1.126:8333
-217.23.11.138:8333
+217.12.199.207:8333
+217.20.130.72:8333
+217.23.6.148:8333
+217.23.140.103:8333
+217.28.96.180:8333
+217.35.130.42:8333
217.111.66.79:8333
-217.155.202.191:8333
217.158.9.102:8333
-217.172.32.18:20993
-220.245.196.37:8333
-[2001:1291:2bf:1::100]:8333
+217.168.143.169:8333
+217.209.32.219:8333
+218.161.33.165:8333
+221.121.144.138:8333
+[2001:0:4137:9e76:2048:3a84:bb91:e846]:8333
+[2001:0:4137:9e76:2066:e9e:b489:f8b8]:8333
+[2001:0:4137:9e76:3854:1211:b5ac:a96b]:8333
+[2001:0:4137:9e76:4e3:1f66:cd4c:829f]:8333
+[2001:0:4137:9e76:ad:1f4:9ea9:fa2e]:8333
+[2001:0:4137:9e76:e5:baa:b66f:f418]:8333
+[2001:0:53aa:64c:20a2:59c4:ad22:93ea]:8333
+[2001:0:53aa:64c:59:617f:a10d:e0]:8333
+[2001:0:5ef5:79fb:200f:3ae5:3cbc:74c9]:8333
+[2001:0:5ef5:79fb:38f2:13b4:b208:5604]:8333
+[2001:0:5ef5:79fd:200b:22a7:cc50:f52d]:8333
+[2001:0:5ef5:79fd:24ef:1aef:a994:303d]:8333
+[2001:0:5ef5:79fd:24fc:b5d:ad4f:4db2]:8333
+[2001:0:5ef5:79fd:28bf:2d23:e02e:c3ef]:8333
+[2001:0:5ef5:79fd:3cd0:3c2e:da44:a759]:8333
+[2001:0:5ef5:79fd:87e:fd7:b1c2:1b4]:8333
+[2001:0:9d38:6ab8:18db:3bda:ab90:e81e]:8333
+[2001:0:9d38:6ab8:4e7:1660:862f:a6d7]:8333
+[2001:0:9d38:6ab8:6:2b:5074:9588]:8333
+[2001:0:9d38:6abd:10f8:a7d7:bb90:f524]:8333
+[2001:13d8:1c01:1000::11]:8333
+[2001:15c0:65ff:610::2]:8333
+[2001:1608:10:156:ae::4adb]:8333
+[2001:1620:b1b:8888:20d:b9ff:fe41:6710]:8333
+[2001:1620:b1b:face:20d:b9ff:fe41:6710]:8333
[2001:1620:f00:282::2]:8333
[2001:1620:f00:8282::1]:8333
-[2001:19f0:5000:8de8:5400:ff:fe12:55e4]:8333
-[2001:19f0:6c00:9103:5400:ff:fe10:a8d3]:8333
-[2001:1b60:3:172:142b:6dff:fe7a:117]:8333
-[2001:410:a000:4050:8463:90b0:fffb:4e58]:8333
+[2001:1680:101:1ae::1]:8333
+[2001:16d8:ff00:85de:20c:29ff:fe52:9594]:8333
+[2001:19f0:4400:434d:5400:ff:fe42:2678]:8333
+[2001:19f0:5000:8c8b:5400:ff:fe1f:c023]:8333
+[2001:19f0:5000:8ce6:5400:ff:fe1b:24a9]:8333
+[2001:19f0:5:314:5400:ff:fe2c:42e8]:8333
+[2001:19f0:5:51b:5400:ff:fe49:fe5b]:8333
+[2001:19f0:5:bc:5400:ff:fe3b:9339]:8333
+[2001:1af8:4020:a020:5::]:8333
+[2001:1bc8:1a0:590e:2e0:f4ff:fe16:3a39]:8333
+[2001:1c04:1401:8f00:f4fe:4fff:fe0c:df40]:8333
+[2001:4128:6135:10:20c:29ff:fe69:9e81]:8333
[2001:4128:6135:2010:21e:bff:fee8:a3c0]:8333
-[2001:41d0:1008:761::17c]:8333
+[2001:4128:6135:e001:5054:ff:fe37:e9eb]:8333
+[2001:41d0:1000:1024::]:8333
+[2001:41d0:1000:1433::]:8333
+[2001:41d0:1004:22ae::]:8333
+[2001:41d0:1004:2996::]:8333
+[2001:41d0:1008:11e0::1a5c:6d9d]:8333
+[2001:41d0:1008:11e0::b74:baf7]:8333
+[2001:41d0:1008:237a::]:8333
+[2001:41d0:1008:2752::]:8333
+[2001:41d0:1008:494::]:8333
[2001:41d0:1:45d8::1]:8333
-[2001:41d0:1:6cd3::]:8333
+[2001:41d0:1:5630::1]:8333
+[2001:41d0:1:6f57::1]:8333
+[2001:41d0:1:801e::1]:8333
+[2001:41d0:1:8852::1]:8333
[2001:41d0:1:8b26::1]:8333
-[2001:41d0:1:afda::]:8200
+[2001:41d0:1:a5b8::1]:8333
[2001:41d0:1:b26b::1]:8333
[2001:41d0:1:c139::1]:8333
[2001:41d0:1:c8d7::1]:8333
-[2001:41d0:1:f59f::33]:8333
-[2001:41d0:1:f7cc::1]:8333
-[2001:41d0:2:1021::1]:8333
-[2001:41d0:2:37c3::]:8200
-[2001:41d0:2:4797:2323:2323:2323:2323]:8333
-[2001:41d0:2:53df::]:8333
+[2001:41d0:1:d227::]:8333
+[2001:41d0:1:dbc4::1]:8333
+[2001:41d0:1:dc5d::1]:8333
+[2001:41d0:1:e13b::1]:8333
+[2001:41d0:1:ef5b::1]:8333
+[2001:41d0:2:16be::1]:8333
+[2001:41d0:2:203c::1]:8333
+[2001:41d0:2:38c5::1]:8333
+[2001:41d0:2:519::]:8333
[2001:41d0:2:9c94::1]:8333
-[2001:41d0:2:9d3e::1]:8333
-[2001:41d0:2:a24f::]:8333
-[2001:41d0:2:a35a::]:8333
-[2001:41d0:2:b2b8::]:8333
-[2001:41d0:2:c1d9::]:8333
-[2001:41d0:2:c6e::]:8333
+[2001:41d0:2:b792::]:8333
+[2001:41d0:2:bf2a::]:8333
+[2001:41d0:2:c793::]:8333
[2001:41d0:2:c9bf::]:8333
-[2001:41d0:2:f1a5::]:8333
-[2001:41d0:52:a00::105f]:8333
-[2001:41d0:52:cff::6f5]:8333
-[2001:41d0:52:d00::6e2]:8333
-[2001:41d0:8:3e75::1]:8333
-[2001:41d0:8:62ab::1]:8333
+[2001:41d0:303:4f0::]:8333
+[2001:41d0:8:1a8a::1]:8333
+[2001:41d0:8:3fa9::1]:8333
+[2001:41d0:8:4670::1]:8333
+[2001:41d0:8:4f48::1]:8333
[2001:41d0:8:6728::]:8333
-[2001:41d0:8:b30a::1]:8333
-[2001:41d0:8:bc26::1]:8333
-[2001:41d0:8:be9a::1]:8333
-[2001:41d0:8:d984::]:8333
-[2001:41d0:8:eb8b::]:8333
-[2001:41d0:a:13a2::1]:8333
-[2001:41d0:a:2b18::1]:8333
-[2001:41d0:a:2d14::]:8333
-[2001:41d0:a:4558::1df2:76d3]:8333
-[2001:41d0:a:4aaa::]:8333
-[2001:41d0:a:635b::1]:8333
-[2001:41d0:a:63d8::1]:8333
+[2001:41d0:8:72c2:d:242:ac11:2]:8333
+[2001:41d0:8:8007::]:8333
+[2001:41d0:8:a71c::]:8333
+[2001:41d0:8:bccc::1]:8333
+[2001:41d0:8:bd45::1]:8333
+[2001:41d0:8:c67c::]:8333
+[2001:41d0:8:de3d::1]:8333
+[2001:41d0:8:e257::1]:8333
+[2001:41d0:8:e3e4::1]:8333
+[2001:41d0:a:14cc::1]:8333
+[2001:41d0:a:15b2::1]:8333
+[2001:41d0:a:1ac9::1]:8333
+[2001:41d0:a:2496::1]:8333
+[2001:41d0:a:308c::]:8333
+[2001:41d0:a:5879::]:8333
+[2001:41d0:a:6810::1]:8333
+[2001:41d0:a:682d::1]:8333
[2001:41d0:a:6c29::1]:8333
-[2001:41d0:a:f9cd::1]:8333
-[2001:41d0:d:20a4::]:8333
+[2001:41d0:a:f52a::1]:8333
+[2001:41d0:d:111c::]:8333
+[2001:41d0:e:1388::1]:8333
[2001:41d0:e:26b::1]:8333
+[2001:41d0:e:f73::1]:8333
[2001:41d0:fc8c:a200:7a24:afff:fe9d:c69b]:8333
+[2001:41f0:61:0:72f3:95ff:fe09:7521]:8333
[2001:41f0:61::7]:8333
-[2001:41f0::2]:8333
-[2001:44b8:41bd:6101:148e:4022:4950:e861]:8333
-[2001:470:1:2f9:0:1:107a:a301]:8333
-[2001:470:1f0b:ad6::2]:8333
-[2001:470:1f11:12d5::ae1:5611]:8333
+[2001:4428:200:8171:db6:2ff4:9c0e:a2da]:8333
+[2001:470:1f07:151c:baac:6fff:feb7:3ba9]:8333
+[2001:470:1f0b:ad6:a60:6eff:fec6:2323]:8333
+[2001:470:1f11:617::10f]:8333
+[2001:470:1f14:73e::2]:8333
[2001:470:1f14:7d::2]:8333
-[2001:470:27:ce::2]:8333
+[2001:470:1f15:11f8::10]:8333
+[2001:470:1f15:1b95:2c3e:8a9a:24e1:7084]:8333
+[2001:470:1f15:e9b::3ef]:8333
+[2001:470:1f1d:3a9::10]:8333
+[2001:470:25:482::2]:8333
+[2001:470:27:19f::2]:8333
+[2001:470:27:665::2]:8333
+[2001:470:28:365::4]:8333
[2001:470:41:6::2]:8333
-[2001:470:507d:0:6ab5:99ff:fe73:ac18]:8333
-[2001:470:583e::2a]:8333
-[2001:470:5f:5f::232]:8333
-[2001:470:66:119::2]:8333
-[2001:470:6c4f::cafe]:8333
-[2001:470:6f:327:913b:7fe:8545:a4f5]:8333
-[2001:470:7dda:1::1]:8333
-[2001:470:95c1::2]:8333
-[2001:470:b1d0:ffff::1000]:8333
-[2001:470:d00d:0:3664:a9ff:fe9a:5150]:8333
-[2001:470:fab7:1::1]:8333
-[2001:4800:7819:104:be76:4eff:fe05:c828]:8333
-[2001:4800:7819:104:be76:4eff:fe05:c9a0]:8333
+[2001:470:727b::11:14]:8333
+[2001:470:7:2f0::2]:8333
+[2001:470:7:65::2]:8333
+[2001:470:7f85::2]:8333
+[2001:470:8:2e1:5825:39df:3e4c:54a8]:8333
+[2001:470:8:2e1::43]:8333
+[2001:470:8:2e1:ae2a:e257:4470:6350]:8333
+[2001:470:a:c13::2]:8333
[2001:4801:7819:74:b745:b9d5:ff10:a61a]:8333
[2001:4801:7819:74:b745:b9d5:ff10:aaec]:8333
[2001:4801:7828:104:be76:4eff:fe10:1325]:8333
-[2001:4802:7800:1:be76:4eff:fe20:f023]:8333
[2001:4802:7800:2:30d7:1775:ff20:1858]:8333
-[2001:4802:7800:2:be76:4eff:fe20:6c26]:8333
-[2001:4802:7802:101:be76:4eff:fe20:256]:8333
-[2001:4802:7802:103:be76:4eff:fe20:2de8]:8333
-[2001:4830:1100:2e8::2]:8333
-[2001:4b98:dc2:41:216:3eff:fe56:f659]:8333
-[2001:4ba0:fffa:5d::93]:8333
-[2001:4ba0:ffff:1be:1:1005:0:1]:8333
-[2001:4dd0:ff00:867f::3]:8333
+[2001:4ba0:babe:832::]:8333
+[2001:4ba0:cafe:379::1]:8333
+[2001:4ba0:ffee:33::10]:8333
[2001:4dd0:ff00:9a67::9]:8333
-[2001:5c0:1400:b::3cc7]:8333
[2001:610:1b19::3]:8333
[2001:610:600:a41::2]:8333
-[2001:67c:26b4::]:8333
-[2001:8d8:840:500::39:1ae]:8333
-[2001:8d8:965:4a00::10:9343]:8333
-[2001:980:4650:1:2e0:53ff:fe13:2449]:8333
+[2001:678:174:4021::2:8333]:8333
+[2001:67c:16dc:1201:5054:ff:fe17:4dac]:8333
+[2001:67c:2128:ffff:6062:36ff:fe30:6532]:8333
+[2001:67c:2564:331:3547:6e28:85a4:fb27]:8333
+[2001:6a0:200:368::2]:8333
+[2001:718:801:311:5054:ff:fe19:c483]:8333
+[2001:7b8:2ff:8f::2]:8333
+[2001:8d8:8a6:4400::3f:86c]:8333
+[2001:8d8:923:8400::87:ebd]:8333
+[2001:960:66d::2]:8333
[2001:981:46:1:ba27:ebff:fe5b:edee]:8333
-[2001:9c8:53e9:369a:226:2dff:fe1b:7472]:8333
-[2001:9d8:cafe:3::87]:8333
-[2001:b10:11:21:3e07:54ff:fe48:7248]:8333
-[2001:ba8:1f1:f34c::2]:8333
-[2001:bc8:2310:100::1]:8333
-[2001:bc8:3427:101:7a4f:8be:2611:6e79]:8333
-[2001:bc8:3505:200::1]:8333
-[2001:cc0:a004::30:1d]:8333
-[2001:e42:102:1209:153:121:76:171]:8333
-[2002:17ea:14eb::17ea:14eb]:8333
-[2002:2f8:2bc5::2f8:2bc5]:8333
-[2002:4047:482c::4047:482c]:8333
-[2002:45c3:8cca::45c3:8cca]:8333
-[2002:46bb:8a41:0:226:b0ff:feed:5f12]:8888
-[2002:46bb:8c3c:0:8d55:8fbb:15fa:f4e0]:8765
-[2002:4c48:a0fe::4c48:a0fe]:8333
-[2002:4d44:25c8::4d44:25c8]:8333
-[2002:505f:aaa2::505f:aaa2]:8333
-[2002:5bc1:799d::5bc1:799d]:8333
-[2002:6dec:5472::6dec:5472]:8333
-[2002:8c6d:6521:9617:12bf:48ff:fed8:1724]:8333
-[2002:ac52:94e2::ac52:94e2]:8333
-[2002:af7e:3eca::af7e:3eca]:8333
-[2002:b009:20c5::b009:20c5]:8333
-[2002:c06f:39a0::c06f:39a0]:8333
-[2002:c23a:738a::c23a:738a]:8333
-[2002:c70f:7442::c70f:7442]:8333
-[2002:cec5:be4f::cec5:be4f]:8333
-[2002:d149:9e3a::d149:9e3a]:8333
+[2001:ba8:1f1:f069::2]:8333
+[2001:bc8:225f:10e:505:6573:7573:d0a]:8333
+[2001:bc8:2706::1]:8333
+[2001:bc8:323c:100::53]:8333
+[2001:bc8:323c:100::80:4]:8333
+[2001:bc8:323c:100::cafe]:8333
+[2001:bc8:3680:4242::1]:8333
+[2001:bc8:399f:f000::1]:8333
+[2001:bc8:3cbf::5]:8333
+[2001:bc8:4700:2300::19:807]:8333
+[2001:e42:102:1805:160:16:206:31]:8333
+[2002:12f1:3f::12f1:3f]:8333
+[2002:1e2:5349::1e2:5349]:8333
+[2002:1e2:5588::1e2:5588]:8333
+[2002:2501:cf62::2501:cf62]:8333
+[2002:268c:a135::268c:a135]:8333
+[2002:2a33:99db::2a33:99db]:8332
+[2002:2ebc:2c14::7]:8333
+[2002:2f59:2c9c::2f59:2c9c]:11885
+[2002:2f5a:3619::2f5a:3619]:8333
+[2002:2f5a:36a4::2f5a:36a4]:8333
+[2002:2f5a:429::2f5a:429]:8333
+[2002:2f5a:562a::2f5a:562a]:8333
+[2002:3a3b:216::3a3b:216]:8333
+[2002:3dfa:5d23::3dfa:5d23]:8333
+[2002:424f:a052::424f:a052]:8333
+[2002:451e:e922::451e:e922]:8333
+[2002:4540:4b30::4540:4b30]:8333
+[2002:51ab:7cc::51ab:7cc]:8333
+[2002:527:de11::527:de11]:8333
+[2002:5395:7d01::5395:7d01]:8333
+[2002:5395:7d2a::5395:7d2a]:8333
+[2002:5669:e3be::5669:e3be]:8333
+[2002:566a:5d6d::566a:5d6d]:8333
+[2002:59b9:f820::59b9:f820]:8333
+[2002:59f8:ac69::59f8:ac69]:8333
+[2002:5bd4:b65a::5bd4:b65a]:8333
+[2002:5c3f:39db::5c3f:39db]:8333
+[2002:5d33:8d03::5d33:8d03]:8333
+[2002:5d67:49bb::5d67:49bb]:8333
+[2002:5dae:5d5f::5dae:5d5f]:8333
+[2002:5dbe:8cc6::5dbe:8cc6]:8333
+[2002:5dbe:9503::5dbe:9503]:8333
+[2002:5fd3:8944::5fd3:8944]:8333
+[2002:5fd3:9467::5fd3:9467]:8333
+[2002:67f9:6a48::67f9:6a48]:8333
+[2002:67f9:6a4a::67f9:6a4a]:8333
+[2002:67f9:6a95::67f9:6a95]:8333
+[2002:6a0e:3ea8::6a0e:3ea8]:10011
+[2002:6b96:375a::6b96:375a]:8333
+[2002:6ca8:cffb::6ca8:cffb]:8333
+[2002:6caf:234::6caf:234]:8333
+[2002:6dec:58f5::6dec:58f5]:8333
+[2002:6dec:5ac7::6dec:5ac7]:8333
+[2002:7237:4a02::7237:4a02]:20033
+[2002:7237:94fd::7237:94fd]:10011
+[2002:7237:e428::7237:e428]:8333
+[2002:7237:fcf6::7237:fcf6]:20188
+[2002:76c0:96e6::76c0:96e6]:8333
+[2002:7819:7e80::7819:7e80]:7743
+[2002:781a:ea86::781a:ea86]:8333
+[2002:781a:f3c2::781a:f3c2]:14475
+[2002:784c:c2c0::784c:c2c0]:8333
+[2002:784c:ec97::784c:ec97]:8333
+[2002:792b:261a::792b:261a]:8333
+[2002:88f3:8cca::88f3:8cca]:8333
+[2002:88f3:a83c::88f3:a83c]:8333
+[2002:8ac9:516f::8ac9:516f]:8333
+[2002:8b81:6d78::8b81:6d78]:50344
+[2002:8b81:6e5c::8b81:6e5c]:38176
+[2002:8bc4:90a6::8bc4:90a6]:8333
+[2002:ac52:b854::ac52:b854]:8333
+[2002:add0:c14a::add0:c14a]:8333
+[2002:b07e:a70a::b07e:a70a]:8333
+[2002:b27c:c565:1::250]:8333
+[2002:b27c:c565::1]:8333
+[2002:b94d:80f1::b94d:80f1]:8333
+[2002:b982:e26a::b982:e26a]:8333
+[2002:bcd5:3145::bcd5:3145]:8333
+[2002:c08a:d22b::c08a:d22b]:8333
+[2002:c0c7:f8e3::c0c7:f8e3]:32771
+[2002:c1a9:fc5a::c1a9:fc5a]:8333
+[2002:c23f:8fc5::c23f:8fc5]:8333
+[2002:d395:ea6d::d395:ea6d]:8333
[2002:d917:ca5::d917:ca5]:8333
-[2400:8900::f03c:91ff:fe50:153f]:8333
-[2400:8900::f03c:91ff:fe6e:823e]:8333
-[2400:8900::f03c:91ff:fea8:1934]:8333
-[2400:8901::f03c:91ff:fe26:c4d6]:8333
+[2002:d917:e91::d917:e91]:8333
+[2002:db71:f434::db71:f434]:8333
+[2400:2651:161:1000:6847:d40f:aaa3:4848]:8333
[2400:8901::f03c:91ff:fec8:4280]:8333
-[2400:8901::f03c:91ff:fec8:660f]:8333
-[2401:1800:7800:102:be76:4eff:fe1c:559]:8333
[2401:1800:7800:102:be76:4eff:fe1c:a7d]:8333
+[2401:2500:203:10:153:120:156:83]:8333
+[2401:a400:3200:5600:14ee:f361:4bdc:1f7c]:8333
+[2403:4200:403:2::ff]:8333
[2405:aa00:2::40]:8333
-[2600:3c00::f03c:91ff:fe18:59b2]:8333
-[2600:3c00::f03c:91ff:fe26:bfb6]:8333
-[2600:3c00::f03c:91ff:fe33:88e3]:8333
-[2600:3c00::f03c:91ff:fe6e:7297]:8333
-[2600:3c00::f03c:91ff:fe84:8a6e]:8333
+[240b:10:ca20:f0:224:e8ff:fe1f:60d9]:8333
+[240b:250:1e0:2400:b9ef:8fe3:a69a:7378]:8333
+[240d:1a:302:8600:8876:a36d:12ee:f285]:8333
+[2600:3c00::f03c:91ff:fe91:3e49]:8333
+[2600:3c00::f03c:91ff:febb:981e]:8333
[2600:3c01::f03c:91ff:fe18:6adf]:8333
-[2600:3c01::f03c:91ff:fe26:c4b8]:8333
-[2600:3c01::f03c:91ff:fe3b:1f76]:8333
-[2600:3c01::f03c:91ff:fe50:5e06]:8333
-[2600:3c01::f03c:91ff:fe61:289b]:8333
[2600:3c01::f03c:91ff:fe69:89e9]:8333
-[2600:3c01::f03c:91ff:fe84:ac15]:8333
-[2600:3c01::f03c:91ff:fe98:68bb]:8333
-[2600:3c02::f03c:91ff:fe26:713]:8333
-[2600:3c02::f03c:91ff:fe26:c49e]:8333
-[2600:3c02::f03c:91ff:fe84:97d8]:8333
-[2600:3c02::f03c:91ff:fec8:8feb]:8333
+[2600:3c01::f03c:91ff:fe91:6a29]:8333
+[2600:3c01::f03c:91ff:fef1:1eaa]:8333
[2600:3c03::f03c:91ff:fe18:da80]:8333
-[2600:3c03::f03c:91ff:fe26:c49b]:8333
-[2600:3c03::f03c:91ff:fe50:5fa7]:8333
+[2600:3c03::f03c:91ff:fe28:1445]:8333
[2600:3c03::f03c:91ff:fe67:d2e]:8333
-[2600:3c03::f03c:91ff:fe6e:1803]:8333
-[2600:3c03::f03c:91ff:fec8:4bbe]:8333
-[2600:3c03::f03c:91ff:fee4:4e16]:8333
-[2601:18d:8300:58a6::2e4]:8333
-[2601:240:4600:40c0:250:56ff:fea4:6305]:8333
-[2601:581:c200:a719:542c:9cd5:4852:f7d9]:8333
-[2601:647:4900:85f1:ca2a:14ff:fe51:bb35]:8333
-[2601:c2:c002:b300:54a0:15b5:19f7:530d]:8333
-[2602:306:ccff:ad7f:b116:52be:64ba:db3a]:8333
-[2602:ae:1982:9400:846:f78c:fec:4d57]:8333
+[2600:3c03::f03c:91ff:fe89:116f]:8333
+[2600:3c03::f03c:91ff:feb0:5fc4]:8333
+[2600:3c03::f03c:91ff:fee0:233e]:8333
+[2600:3c03::f03c:91ff:fee0:51]:8333
+[2600:8805:2400:14e:226:4aff:fe02:2ba4]:8333
+[2600:8807:5080:3301:1487:83b7:33d7:eb97]:8333
+[2601:186:c100:6bcd:16bd:cea1:235d:1c19]:8333
+[2601:18c:4200:28d0:e4d:e9ff:fec5:76d0]:8333
+[2601:247:8201:6251:30e6:7b95:69bf:9248]:8333
+[2601:602:9980:f78:211:11ff:fec5:1ae]:8333
+[2602:ae:1993:de00:2c50:9a44:8f11:77a5]:8333
+[2602:ff68:0:1:21e:bff:feca:db72]:8333
+[2602:ff68:0:1:2bd:27ff:feb0:adf8]:8333
+[2602:ff68:0:1::5]:8333
+[2602:ff68:0:5:2bd:27ff:feb0:adf8]:8333
[2602:ffc5:1f::1f:2d61]:8333
[2602:ffc5:1f::1f:9211]:8333
-[2602:ffc5::75d5:c1c3]:8333
+[2602:ffc5::9e63:27a2]:8333
+[2602:ffc5::c30:1c75]:8333
[2602:ffc5::ffc5:b844]:8333
[2602:ffe8:100:2::457:936b]:8333
-[2602:ffe8:100:2::9d20:2e3c]:8333
-[2602:ffea:1001:72b::578b]:8333
-[2602:ffea:a::24c4:d9fd]:8333
-[2604:0:c1:100:1ec1:deff:fe54:2235]:8333
-[2604:180:1:1af::42a9]:8333
-[2604:180:3:702::c9de]:8333
-[2604:4080:1114:0:3285:a9ff:fe93:850c]:8333
-[2604:6000:ffc0:3c:64a3:94d0:4f1d:1da8]:8333
-[2605:6000:f380:9a01:ba09:8aff:fed4:3511]:8333
-[2605:6001:e00f:7b00:c587:6d91:6eff:eeba]:8333
-[2605:f700:c0:1::25c3:2a3e]:8333
-[2606:6000:a441:9903:5054:ff:fe78:66ff]:8333
-[2607:5300:100:200::1c83]:9334
-[2607:5300:10::a1]:8333
-[2607:5300:60:1c2f::1]:8333
-[2607:5300:60:2b90::1]:8333
-[2607:5300:60:3320::1]:8333
-[2607:5300:60:385::1]:8333
-[2607:5300:60:4a85::]:8333
-[2607:5300:60:65e4::]:8333
-[2607:5300:60:6918::]:8333
-[2607:5300:60:711a:78::a7b5]:8333
-[2607:5300:60:714::1]:8333
-[2607:5300:60:870::1]:8333
-[2607:5300:60:952e:3733::1414]:8333
-[2607:f1c0:848:1000::48:943c]:8333
-[2607:f2e0:f:5df::2]:8333
-[2607:f748:1200:f8:21e:67ff:fe99:8f07]:8333
-[2607:f948:0:1::7]:8333
-[2607:ff68:100:36::131]:8333
-[2803:6900:1::117]:8333
-[2a00:1098:0:80:1000:25:0:1]:8333
-[2a00:1178:2:43:5054:ff:fe84:f86f]:8333
-[2a00:1178:2:43:5054:ff:fee7:2eb6]:8333
-[2a00:1178:2:43:8983:cc27:d72:d97a]:8333
-[2a00:1328:e100:cc42:230:48ff:fe92:55c]:8333
+[2604:180:2:eee::ca46]:8333
+[2604:880:d:85::be37]:8333
+[2604:9a00:2100:a009:2::]:8333
+[2604:a880:2:d0::301:8001]:8333
+[2604:a880:2:d0::4a9:1001]:8333
+[2604:a880:2:d0::53a:c001]:8333
+[2604:a880:400:d0::ad7:e001]:8333
+[2604:a880:400:d0::dcf:f001]:8333
+[2605:4d00::50]:8333
+[2605:6000:edc8:300::ddfe]:8333
+[2605:6000:ffc0:70:74d5:225c:f553:5bb8]:8333
+[2606:6000:c148:7003:5054:ff:fe78:66ff]:8333
+[2606:6000:e6d6:d701:d428:5e44:a2c9:3ff6]:8333
+[2606:c680:1:4a:2016:d1ff:fe93:52a7]:8333
+[2607:5300:203:118:3733::1414]:8333
+[2607:5300:60:13bb::1]:8333
+[2607:5300:60:1966::1]:8333
+[2607:5300:60:2218::]:8333
+[2607:5300:60:3775::]:8333
+[2607:5300:60:3ddf::]:8333
+[2607:5300:60:a654::]:8333
+[2607:5300:60:a7a3::]:8333
+[2607:5300:60:ac0::1]:8333
+[2607:5300:60:cf97::]:8333
+[2607:f0d0:1901:19::6]:8333
+[2607:f128:40:1202:69:162:139:125]:8333
+[2607:f128:40:1703::2]:8333
+[2607:f178:0:8::106]:8333
+[2607:f1c0:84d:8900::7e:cad]:8333
+[2607:f948:0:1::1:40]:8333
+[2607:fcd0:100:2302::6094:635a]:8333
+[2607:fcd0:100:6a00::3a96:1]:8333
+[2607:fcd0:100:6a02::7ff0:1]:8333
+[2607:fcd0:100:8203::8c58:dbc]:8333
+[2607:fea8:1360:9c2:221a:6ff:fe47:776d]:8333
+[2607:fea8:4da0:9ce:5114:a8ec:20f5:a50b]:8333
+[2607:fea8:5df:fda0:feaa:14ff:feda:c79a]:8333
+[2607:fea8:84c0:163:f42c:baff:fecc:6bbf]:8333
+[2607:ff10:c5:502:225:90ff:fe32:d446]:8333
+[2607:ff48:aa81:800::96cf:1]:8333
+[2620:11c:5001:1118:d267:e5ff:fee9:e673]:8333
+[2620:b8:4000:1000::93:1]:8333
+[2800:1a0::9]:8333
+[2a00:1178:2:43:19fd:d43e:b77:edeb]:8333
+[2a00:1178:2:43:b4e3:e562:f811:d761]:8333
[2a00:14f0:e000:80d2:cd1a::1]:8333
+[2a00:1630:14::101]:8333
[2a00:1630:2:1802:188:122:91:11]:8333
-[2a00:18e0:0:1800::1]:8333
-[2a00:18e0:0:dcc5:109:234:106:191]:8333
-[2a00:1a28:1157:87::94c7]:8333
+[2a00:1630:2:500::4]:8333
+[2a00:1768:2001:24::148:218]:8333
+[2a00:1768:2001:27::142:21]:8333
+[2a00:1a48:7810:101:be76:4eff:fe08:c774]:8333
[2a00:1ca8:37::a5fc:40d1]:8333
[2a00:1ca8:37::ab6d:ce2c]:8333
-[2a00:7143:100:0:216:3eff:fe2e:74a3]:8333
-[2a00:7143:100:0:216:3eff:fed3:5c21]:8333
-[2a00:7c80:0:45::123]:8333
+[2a00:1dc0:2255:10::2]:8333
+[2a00:7c80:0:71::8]:8333
+[2a00:7c80:0:97::7]:8333
+[2a00:bbe0:0:42:222:64ff:fe9a:e206]:8333
+[2a00:c98:2050:a020:3::110]:8333
+[2a00:dcc0:eda:98:183:193:1d24:b53a]:8333
[2a00:dcc0:eda:98:183:193:c382:6bdb]:8333
[2a00:dcc0:eda:98:183:193:f72e:d943]:8333
-[2a00:f820:17::4af:1]:8333
-[2a00:f940:2:1:2::101d]:8333
-[2a00:f940:2:1:2::6ac]:8333
-[2a01:1b0:7999:402::131]:8333
-[2a01:238:42dd:f900:7a6c:2bc6:4041:c43]:8333
-[2a01:238:4313:6300:2189:1c97:696b:5ea]:8333
-[2a01:488:66:1000:5c33:91f9:0:1]:8333
-[2a01:488:66:1000:b01c:178d:0:1]:8333
+[2a00:f90:ff0:c100:53c4:97a7:8b59:796a]:8333
+[2a01:238:435c:de00:b110:38cf:192d:b2c]:28333
+[2a01:348:6:7cf::2]:8333
+[2a01:368:e012:8888:216:3eff:fe24:1162]:8333
+[2a01:488:66:1000:53a9:22b:0:1]:8333
+[2a01:488:67:1000:523:ffa7:0:1]:8333
+[2a01:488:67:1000:b01c:3379:0:1]:8333
[2a01:4f8:100:34ce::2]:8333
-[2a01:4f8:100:34e4::2]:8333
[2a01:4f8:100:44e7::2]:8333
-[2a01:4f8:100:510e::2]:8333
-[2a01:4f8:100:5128::2]:8333
-[2a01:4f8:110:5105::2]:8333
-[2a01:4f8:110:516c::2]:8333
+[2a01:4f8:10a:2e4::2]:8333
+[2a01:4f8:10a:34e::2]:8333
+[2a01:4f8:10a:51d::2]:8333
+[2a01:4f8:10a:622::2]:8333
+[2a01:4f8:10a:85f::2]:8333
+[2a01:4f8:10a:864::2]:8333
+[2a01:4f8:10a:d04::2]:8333
+[2a01:4f8:110:334c::2]:8333
+[2a01:4f8:110:536e::2]:8333
[2a01:4f8:120:43e4::2]:8333
-[2a01:4f8:120:62e6::2]:8333
[2a01:4f8:120:702e::2]:8333
-[2a01:4f8:120:8203::2]:8333
-[2a01:4f8:121:234d::2]:8333
-[2a01:4f8:121:261::2]:8333
-[2a01:4f8:130:11ea::2]:8333
+[2a01:4f8:121:4346::2]:8333
[2a01:4f8:130:3332::2]:8333
-[2a01:4f8:130:40ab::2]:8333
-[2a01:4f8:130:632c::2]:8333
-[2a01:4f8:130:6366::2]:8333
-[2a01:4f8:130:934f::2]:8333
+[2a01:4f8:131:33ad::2]:8333
[2a01:4f8:131:33ad:fea1::666]:8333
-[2a01:4f8:140:2195::2]:8333
-[2a01:4f8:140:6333::2]:8333
-[2a01:4f8:140:930d::2]:8333
+[2a01:4f8:140:31b0::2]:8333
+[2a01:4f8:140:4088::2]:8333
+[2a01:4f8:140:931a::2]:8333
[2a01:4f8:140:93b0::2]:8333
-[2a01:4f8:141:1167::2]:8333
+[2a01:4f8:141:13ad::c451]:8333
[2a01:4f8:141:186::2]:8333
-[2a01:4f8:141:53f0::2]:8333
-[2a01:4f8:150:336a::2]:8333
-[2a01:4f8:150:72ee::4202]:8333
-[2a01:4f8:150:8324::2]:9001
-[2a01:4f8:151:21ca::2]:8333
-[2a01:4f8:151:41c2:0:5404:a67e:f250]:8333
-[2a01:4f8:151:5128::2]:8333
+[2a01:4f8:141:22ae::2]:8333
+[2a01:4f8:141:322c::2]:8333
+[2a01:4f8:150:11d4::2]:8333
+[2a01:4f8:150:440f::2]:8333
+[2a01:4f8:150:61ee::2]:8333
+[2a01:4f8:150:726b::2]:8333
+[2a01:4f8:151:30c9::2]:15000
+[2a01:4f8:151:41a2::2]:8333
+[2a01:4f8:151:41cc::2]:8333
[2a01:4f8:151:52c6::154]:8333
-[2a01:4f8:151:6347::2]:9001
-[2a01:4f8:160:5136::2]:8333
-[2a01:4f8:160:72c5::2858:e1c5]:8333
-[2a01:4f8:160:72c5::593b:60d5]:8333
+[2a01:4f8:151:600b::1:1]:8333
+[2a01:4f8:151:7175::2]:8333
+[2a01:4f8:160:41f0::1:33]:8333
+[2a01:4f8:160:5328::27f0:187a]:8333
[2a01:4f8:160:814f::2]:8333
-[2a01:4f8:161:13d0::2]:8333
-[2a01:4f8:161:228f::2]:8333
-[2a01:4f8:161:51c4::2]:8333
-[2a01:4f8:161:60a7::2]:8333
+[2a01:4f8:161:21ad::333:30]:8333
[2a01:4f8:161:7026::2]:8333
-[2a01:4f8:161:9184::2]:8333
-[2a01:4f8:162:2108::2]:8333
-[2a01:4f8:162:218c::2]:8333
-[2a01:4f8:162:4443::2]:8333
-[2a01:4f8:162:51a3::2]:8333
+[2a01:4f8:162:4110::2]:8333
+[2a01:4f8:162:4348::2]:8333
+[2a01:4f8:171:1c1b::2]:8333
+[2a01:4f8:171:1c3::2]:8333
+[2a01:4f8:171:2258::2]:8333
+[2a01:4f8:171:2a70::2]:8333
+[2a01:4f8:171:2e1b::2]:8333
+[2a01:4f8:171:2f28::2]:8333
+[2a01:4f8:171:3248::2]:8333
+[2a01:4f8:171:380c::2]:8333
[2a01:4f8:171:b93::2]:8333
-[2a01:4f8:190:1483::1]:8333
-[2a01:4f8:190:4495::2]:8333
-[2a01:4f8:190:64c9::2]:8333
+[2a01:4f8:171:d0a::2]:8333
+[2a01:4f8:172:116c::2]:8333
+[2a01:4f8:172:1287::2]:8333
+[2a01:4f8:172:17a9::2]:8333
+[2a01:4f8:172:1ca7::2]:8333
+[2a01:4f8:172:2159::2]:8333
+[2a01:4f8:172:3a41::2]:8333
+[2a01:4f8:172:3b42::2]:8333
+[2a01:4f8:172:3ec1::2]:8333
+[2a01:4f8:172:3ec2::2]:8333
+[2a01:4f8:172:aeb::2]:8333
+[2a01:4f8:172:aec::2]:8333
+[2a01:4f8:173:10ab::2]:8333
+[2a01:4f8:173:1551::2]:8333
+[2a01:4f8:173:1bca::2]:8333
+[2a01:4f8:173:1e2e::2]:8333
+[2a01:4f8:173:2162::2]:8333
+[2a01:4f8:173:21e6::2]:8333
+[2a01:4f8:173:42::2]:8333
+[2a01:4f8:173:cc1::2]:8333
+[2a01:4f8:190:1253::2]:8333
+[2a01:4f8:190:24eb::2]:8333
+[2a01:4f8:190:34f0::2]:8333
+[2a01:4f8:190:528d::2]:8333
[2a01:4f8:190:91ce::2]:8333
[2a01:4f8:191:2194::83]:8333
[2a01:4f8:191:40e8::2]:8333
-[2a01:4f8:191:44b4::2]:8333
-[2a01:4f8:191:8242::2]:8333
-[2a01:4f8:191:83a2::2]:8333
-[2a01:4f8:192:11b2::2]:8333
+[2a01:4f8:191:8165::2]:22556
+[2a01:4f8:191:81b7::2]:8333
+[2a01:4f8:191:8328::3]:8333
+[2a01:4f8:192:11b2::2]:8343
[2a01:4f8:192:216c::2]:8333
-[2a01:4f8:192:22b3::2]:8333
+[2a01:4f8:192:22af::2]:8333
+[2a01:4f8:192:2422::2]:8333
+[2a01:4f8:192:34d0::2]:8333
[2a01:4f8:192:440b::2]:8333
+[2a01:4f8:192:5230::2]:8333
[2a01:4f8:192:db::2]:8333
[2a01:4f8:200:1012::2]:8333
-[2a01:4f8:200:23d1::dead:beef]:8333
-[2a01:4f8:200:506d::2]:8333
-[2a01:4f8:200:51f0::2]:8333
-[2a01:4f8:200:5389::2]:8333
-[2a01:4f8:200:53e3::2]:8333
-[2a01:4f8:200:6344::2]:8333
-[2a01:4f8:200:6396::2]:8333
-[2a01:4f8:200:63af::119]:8333
-[2a01:4f8:200:71e3:78b4:f3ff:fead:e8cf]:8333
-[2a01:4f8:201:214c::2]:8333
-[2a01:4f8:201:233:1::3]:8333
-[2a01:4f8:201:3e3::2]:8333
+[2a01:4f8:200:414e::2]:8333
+[2a01:4f8:200:416a::2]:8333
+[2a01:4f8:201:21a7::2]:8333
+[2a01:4f8:201:4017::11]:8333
[2a01:4f8:201:6011::4]:8333
[2a01:4f8:201:60d5::2]:8333
-[2a01:4f8:202:265::2]:8333
-[2a01:4f8:202:3115::2]:8333
+[2a01:4f8:202:12d6::2]:8333
[2a01:4f8:202:31e3::2]:8333
-[2a01:4f8:202:31ef::2]:8333
-[2a01:4f8:202:3392::2]:8333
+[2a01:4f8:202:32c6::2]:8333
[2a01:4f8:202:53c3::2]:8333
-[2a01:4f8:202:63f4::2]:8333
-[2a01:4f8:202:7227::2]:8333
-[2a01:4f8:210:2227::2]:8333
-[2a01:4f8:210:24aa::2]:8333
[2a01:4f8:211:14cf::2]:8333
-[2a01:4f8:211:181b::2]:8333
-[2a01:4f8:212:289e::2]:8333
-[2a01:4f8:212:33db::2]:18333
-[2a01:4f8:a0:112f::2]:8333
-[2a01:4f8:a0:3174::2]:8333
-[2a01:4f8:a0:328c::2]:8333
-[2a01:4f8:a0:5243::2]:8333
-[2a01:4f8:c17:19b9::2]:8333
-[2a01:4f8:c17:1a41::2]:8333
-[2a01:4f8:c17:1a92::2]:8333
-[2a01:4f8:c17:273::2]:8333
-[2a01:4f8:c17:435::2]:8333
-[2a01:4f8:c17:755::2]:8333
-[2a01:4f8:c17:b54::2]:8333
-[2a01:4f8:d16:9384::2]:8333
+[2a01:4f8:211:1ec5::2]:8333
+[2a01:4f8:211:483::2]:8333
+[2a01:4f8:211:d99::8]:8333
+[2a01:4f8:212:1826::2]:8333
+[2a01:4f8:212:27a8::2]:8333
+[2a01:4f8:221:801::2]:8333
+[2a01:4f8:a0:12cc::2]:8333
+[2a01:4f8:a0:746a:101:1:1:2]:8333
+[2a01:4f8:a0:828a::2]:8333
+[2a01:4f8:c17:2eef::2]:8333
+[2a01:4f8:c17:2f3c::2]:3333
+[2a01:4f8:c17:3b02::2]:8333
+[2a01:4f8:c17:4245::2]:8333
+[2a01:4f8:c17:464f::2]:8333
+[2a01:4f8:c17:4a1c::2]:8333
+[2a01:4f8:c17:4c5d::2]:8333
+[2a01:4f8:c17:67f8::2]:8333
+[2a01:4f8:c17:6dd0::2]:8333
+[2a01:4f8:c17:710b::2]:8333
+[2a01:4f8:c17:714::2]:8333
+[2a01:4f8:c17:72c6::2]:8333
[2a01:608:ffff:a009:8bf5:879d:e51a:f837]:8333
-[2a01:680:10:10:f2de:f1ff:fec9:dc0]:8333
-[2a01:7c8:aaac:1f6:5054:ff:fe30:e585]:8333
-[2a01:7c8:aaac:20b:5054:ff:fe24:435e]:8333
+[2a01:680:10:10::1]:8333
+[2a01:6f0:ffff:120::8dcb]:8333
+[2a01:79c:cebc:857c:98c1:88ff:fef5:90de]:8333
+[2a01:79d:7377:2629:7e57:7e57:1:1]:8333
[2a01:7c8:aaac:43d:5054:ff:fe4e:3dd4]:8333
-[2a01:7c8:aaad:256::1]:8333
-[2a01:7c8:aab6:ea:5054:ff:feff:eac3]:8333
-[2a01:7c8:aab9:5a:5054:ff:fe89:7b26]:8333
-[2a01:7c8:aabc:2c8:5054:ff:fe35:6581]:8333
-[2a01:7e00::f03c:91ff:fe18:301e]:8333
-[2a01:7e00::f03c:91ff:fe18:3942]:8333
+[2a01:7c8:aab5:3e6:5054:ff:fed7:4e54]:8333
+[2a01:7c8:aabd:3d5:5054:ff:fe95:f586]:8333
+[2a01:7c8:aac1:453:d0d2:af96:fa88:5d0e]:8333
+[2a01:7c8:aac3:663:5054:ff:fe25:8c69]:8333
+[2a01:7c8:aac3:97:5054:ff:fea7:3780]:8333
+[2a01:7c8:aac4:567:5054:ff:fedc:518a]:8333
[2a01:7e00::f03c:91ff:fe26:8c87]:8333
-[2a01:7e00::f03c:91ff:fe50:6206]:8333
-[2a01:7e00::f03c:91ff:fe67:559d]:8333
-[2a01:7e00::f03c:91ff:fe84:434f]:8333
+[2a01:7e00::f03c:91ff:fe50:94b8]:8333
+[2a01:7e00::f03c:91ff:fe55:2c]:8333
[2a01:7e00::f03c:91ff:fe89:1143]:8333
-[2a01:7e00::f03c:91ff:fe98:2505]:8333
-[2a01:7e00::f03c:91ff:fedb:352e]:8333
-[2a01:7e01::f03c:91ff:fec8:d7b5]:8333
-[2a01:e34:ee33:1640:c504:f677:b28a:ba42]:8333
-[2a01:e35:2e7e:bc0:e079:f55e:cef3:b5d7]:8333
+[2a01:7e00::f03c:91ff:fe89:53fd]:8333
+[2a01:7e00::f03c:91ff:fedf:b70f]:8333
+[2a01:b000::4166:515b:ef9e:b3]:8333
+[2a01:b2e0:2::40]:8333
+[2a01:e34:ec29:24c0:f3:ddaf:9f59:586f]:8333
+[2a01:e34:eed7:6670:ec1b:bf7c:b012:6069]:8333
[2a01:e35:2ee5:610:21f:d0ff:fe4e:7460]:8333
[2a01:e35:8a3f:47c0:c617:feff:fe3c:9fbd]:8333
-[2a01:e35:8aca:6a0:211:aff:fe5e:295e]:8333
-[2a02:180:a:18:81:7:11:50]:8333
-[2a02:1810:1d87:6a00:5604:a6ff:fe60:d87d]:8333
-[2a02:2168:1144:5c01:d63d:7eff:fedd:4f8e]:8333
-[2a02:2498:6d7b:7001:b508:b39d:2cea:5b7a]:8333
-[2a02:2528:503:2::15]:8333
-[2a02:2528:fa:1a56:216:44ff:fe6a:d112]:8333
-[2a02:27f8:2012:0:e9f7:268f:c441:6129]:8333
+[2a01:e35:8bff:70b0:1e1b:dff:fe0b:236d]:8333
+[2a02:1205:34c3:a4e0:d63d:7eff:fe98:10c8]:8333
+[2a02:1205:34da:aa00:5882:249d:ddbf:bc43]:8333
+[2a02:1205:5051:a640:d6ae:52ff:fea3:ac]:8333
+[2a02:1205:c689:d980:baae:edff:feea:9445]:8333
+[2a02:120b:2c2a:5ec0:10dd:31ff:fe42:5079]:8333
+[2a02:120b:2c35:69d0:219:99ff:fe6b:4ec3]:8333
+[2a02:120b:c3c2:ff60:21f:5bff:fec3:a7ad]:24312
+[2a02:13b8:4000:1000:216:e6ff:fe92:8619]:8333
+[2a02:13b8:4000:1000::27]:8333
+[2a02:17d0:2a:4400:40f:3dd4:b053:47ad]:8333
+[2a02:180:1:1::517:afb]:8333
+[2a02:180:6:1::18]:8333
+[2a02:1810:1d11:f900:6872:f28e:8126:f635]:8333
+[2a02:27a8:0:1:52e5:49ff:fee3:3b49]:8333
[2a02:348:86:3011::1]:8333
-[2a02:4780:1:1::1:8a01]:8333
-[2a02:578:5002:116::2]:8333
+[2a02:390:9000:0:218:7dff:fe10:be33]:8333
+[2a02:582:78c1:7600:2d49:6212:29d3:abb]:8333
[2a02:6080::1:190b:69e3]:8333
-[2a02:6080::1:e893:d9d6]:8333
-[2a02:770:4000::139]:8333
+[2a02:750:7:3305::575]:8333
+[2a02:752:100:3::53]:8333
+[2a02:7aa0:1201::7501:d950]:8333
[2a02:7aa0:1201::deb3:81a2]:8333
-[2a02:8010:b001::5860:59b5]:8333
-[2a02:810d:21c0:f00:a248:1cff:feb8:5348]:8333
-[2a02:a50::21b:24ff:fe93:4e39]:8333
-[2a02:a80:0:1200::2]:8333
-[2a02:c200:0:10:2:1:5830:1]:8333
-[2a02:c200:0:10:2:5:4692:1]:8333
-[2a02:c200:0:10:3:0:7158:1]:8333
-[2a02:c200:0:10::2244:1]:8333
-[2a02:c200:1:10:2:3:3339:1]:8333
-[2a02:c200:1:10:2:3:7844:1]:8333
-[2a02:c200:1:10:2:5:6288:1]:8333
-[2a02:c200:1:10:3:0:5912:1]:8333
+[2a02:7aa0:1619::a037:69a6]:8333
+[2a02:810d:14c0:8694:d250:99ff:fe81:23d9]:8333
+[2a02:a50::dacb:8aff:fe36:8d2d]:8333
+[2a02:c200:0:10:3:0:2591:1]:8333
+[2a02:c200:1:10:2:5:9982:1]:8333
+[2a02:c200:1:10:3:0:9290:1]:8333
+[2a02:c205:3000:7158::1]:8333
+[2a02:c205:3001:4522::1]:8333
+[2a02:c205:3001:6549::1]:8333
+[2a02:c207:2008:3772::1]:8333
+[2a02:c207:2008:6519::1]:8333
+[2a02:c207:2009:213::1]:8333
+[2a02:c207:2009:7858::1]:8333
+[2a02:c207:2010:302::1]:8333
+[2a02:c207:3001:5824::1]:8333
+[2a02:ce80:0:20::1]:8333
[2a03:4000:2:496::8]:8333
+[2a03:4000:6:416c::53]:8333
[2a03:4000:6:8009::1]:8333
-[2a03:4000:6:8063::bcd0]:8333
-[2a03:4900:fffc:b::2]:8333
-[2a03:b0c0:1:d0::d:5001]:8333
+[2a03:4000:9:8e::1]:8333
+[2a03:7380:2140:17:51fe:3519:b571:4a13]:8333
+[2a03:b0c0:0:1010::7a3:1001]:8333
+[2a03:b0c0:0:1010::7aa:4001]:8333
+[2a03:b0c0:3:d0::1b99:c001]:8333
+[2a03:b0c0:3:d0::1b99:e001]:8333
+[2a03:b0c0:3:d0::1b9a:3001]:8333
+[2a03:b0c0:3:d0::2208:6001]:8333
+[2a03:b0c0:3:d0::23f7:1001]:8333
+[2a03:b0c0:3:d0::23f7:9001]:8333
+[2a03:b0c0:3:d0::23fb:2001]:8333
+[2a03:b0c0:3:d0::23fb:3001]:8333
+[2a03:b0c0:3:d0::23fb:5001]:8333
+[2a03:b0c0:3:d0::23fb:7001]:8333
+[2a03:b0c0:3:d0::2400:1]:8333
+[2a03:b0c0:3:d0::2400:3001]:8333
+[2a03:b0c0:3:d0::2400:e001]:8333
+[2a03:b0c0:3:d0::2401:e001]:8333
+[2a03:b0c0:3:d0::2402:2001]:8333
+[2a03:b0c0:3:d0::2402:8001]:8333
+[2a03:b0c0:3:d0::2402:9001]:8333
+[2a03:b0c0:3:d0::2402:b001]:8333
+[2a03:b0c0:3:d0::2402:d001]:8333
+[2a03:b0c0:3:d0::2403:1001]:8333
+[2a03:b0c0:3:d0::2403:2001]:8333
+[2a03:b0c0:3:d0::2403:4001]:8333
+[2a03:b0c0:3:d0::2403:6001]:8333
+[2a03:b0c0:3:d0::2403:a001]:8333
+[2a03:b0c0:3:d0::2403:b001]:8333
+[2a03:b0c0:3:d0::2403:f001]:8333
+[2a03:b0c0:3:d0::2404:6001]:8333
+[2a03:b0c0:3:d0::2404:b001]:8333
[2a03:f80:ed15:149:154:155:235:1]:8333
-[2a03:f80:ed15:149:154:155:241:1]:8333
-[2a03:f80:ed16:ca7:ea75:b12d:2af:9e2a]:8333
-[2a04:1980:3100:1aab:290:faff:fe70:a3d8]:8333
-[2a04:1980:3100:1aab:e61d:2dff:fe29:f590]:8333
-[2a04:2f80:6:200::89]:8333
-[2a04:ac00:1:4a0b:5054:ff:fe00:5af5]:8333
-[2a04:ad80:0:68::35da]:8333
-3ffk7iumtx3cegbi.onion:8333
+[2a04:1980:3100:1aac:e61d:2dff:fe29:f241]:8333
+[2a04:1980:3100:1aac:e61d:2dff:fe29:f251]:8333
+[2a04:2180:0:1::5a49:3c06]:8333
+[2a04:2180:1:7::3]:8333
+[2a04:2e00:5:2e:9a4b:e1ff:fe62:6dc0]:8333
+[2a04:3542:1000:910:8492:b8ff:fe91:711d]:8333
+[2a04:dbc3:fffe:0:e61f:13ff:fe95:8401]:8333
+[2a06:9fc0:2a06:9fc0:2a06:9fc1:67c:e706]:8333
+[2c0f:f738:2004:82::]:8333
+2hryb3uh3tzwgnya.onion:8333
3nmbbakinewlgdln.onion:8333
-4j77gihpokxu2kj4.onion:8333
-546esc6botbjfbxb.onion:8333
-5at7sq5nm76xijkd.onion:8333
-77mx2jsxaoyesz2p.onion:8333
-7g7j54btiaxhtsiy.onion:8333
-a6obdgzn67l7exu3.onion:8333
-ab64h7olpl7qpxci.onion:8333
-am2a4rahltfuxz6l.onion:8333
-azuxls4ihrr2mep7.onion:8333
-bitcoin7bi4op7wb.onion:8333
-bitcoinostk4e4re.onion:8333
+3qeri3tmhzmpegyv.onion:8333
+4wdknmecghcmclq5.onion:8333
+53tsjt6zq3iasv5q.onion:8333
+5cg7qeywvwo6vxpt.onion:8333
+5gbcrgqxcbxj253s.onion:8333
+6cn4ilbwkrkh7gwo.onion:8333
+6e4jrnn7igeqxmlf.onion:8333
+6ymgbvnn6d5nfmv4.onion:8333
+6zsh3bfduhpo7ldl.onion:8333
+72fq6phv4fg4rhvh.onion:8333
+7gdqp6npusk4lfwk.onion:8333
+a7emxol55e623lqc.onion:8333
+assbiydziq77zaki.onion:8333
+bafk5ioatlgt7dgl.onion:8333
bk7yp6epnmcllq72.onion:8333
-bmutjfrj5btseddb.onion:8333
-ceeji4qpfs3ms3zc.onion:8333
-clexmzqio7yhdao4.onion:8333
+brwqezn6le54w2bb.onion:8333
+bs4bq6s6qkvt5hpi.onion:8333
+bup5n5e3kurvjzf3.onion:8333
+c2tpqkaz4ihjzwgb.onion:8333
+cernrmrk5zomzozn.onion:8333
+cfyegj64ht3jpodr.onion:8333
+cg5vg54cazzpvoug.onion:8333
+cgk4u2lxrvml4jvb.onion:8333
+cjygd7pu5lqkky5j.onion:8333
+d6wubsdtr46dd5ki.onion:8333
+dfq6yjc3aelplwr4.onion:8333
+dqpxwlpnv3z3hznl.onion:8333
+eamfospuveabaimd.onion:8333
+ep2mjzox3kvb6ax4.onion:8333
+fpbxb4wjudiw2w5a.onion:8333
+fu5hfsbbf5jwsvhv.onion:8333
+g4freoibsczujle3.onion:8333
gb5ypqt63du3wfhn.onion:8333
-h2vlpudzphzqxutd.onion:8333
-n42h7r6oumcfsbrs.onion:4176
-ncwk3lutemffcpc4.onion:8333
+ggdy2pb2avlbtjwq.onion:8333
+gh2aiddzxmvyrnue.onion:8333
+gnxgylbgzvaazkq7.onion:8333
+hnizdxnejel64ubk.onion:8333
+htvdcmlc3abji2ab.onion:8443
+hwuboois4gslupgx.onion:8333
+hxz6gowludlj6d5a.onion:8333
+j6umo4bnsztpsonc.onion:8333
+jdunmaocwbbnw565.onion:8333
+ktv3qlxl7xvmdlf4.onion:8333
+kvd44sw7skb5folw.onion:8333
+kwimnzm6vd4zakvl.onion:8333
+la5xhk3lprxzxmz2.onion:8333
+lc7cx67end26uutp.onion:8352
+mwu5og2agcspmgkx.onion:8333
+mzxkipiyekaoh7my.onion:8333
+n6rwlrtwpqc7qwo7.onion:8333
+nj36424yccqph62z.onion:8333
+o256w7t3vcgktmxk.onion:8333
+o4sl5na6jeqgi3l6.onion:8333
okdzjarwekbshnof.onion:8333
-pjghcivzkoersesd.onion:8333
-rw7ocjltix26mefn.onion:8333
-uws7itep7o3yinxo.onion:8333
-vk3qjdehyy4dwcxw.onion:8333
+oyebydl2pacx6v26.onion:8333
+p5mx2imj75dpmime.onion:8333
+psco6bxjewljrczx.onion:8333
+pxtgswet6tlgrbwj.onion:8333
+rb4v3fhgx2zr4rre.onion:8333
+rjlnp3hwvrsmap6e.onion:8333
+rlafimkctvz63llg.onion:8333
+rxjvy5eyttep5tts.onion:8333
+seoskudzk6vn6mqz.onion:8333
+tpgdufxxsw3jkrdf.onion:8333
+tuiyvqgi3o675pjb.onion:8333
+tx4zd7d5exonnblh.onion:8333
+uokg6avfgbhofls3.onion:8333
+v3gjphgqy5hygcml.onion:8333
+vhdoxqq63xr53ol7.onion:8333
+visevrizz3quyagj.onion:8333
vqpye2k5rcqvj5mq.onion:8333
-wpi7rpvhnndl52ee.onion:8333
+wfsx2gi7djhy22hk.onion:8333
+wg6vwmbrzyyzapun.onion:8333
+xub4w3w4wwk56xiq.onion:8333
+ycivnom44dmxx4ob.onion:8333
+ywskufc62bf2fum4.onion:8333
+z4fax2vxg23t2ddf.onion:8333
+zo5dklwelmdrpo5n.onion:8333
diff --git a/contrib/spendfrom/README.md b/contrib/spendfrom/README.md
deleted file mode 100644
index c0a9c9ccf9..0000000000
--- a/contrib/spendfrom/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-### SpendFrom ###
-
-Use the raw transactions API to send coins received on a particular
-address (or addresses).
-
-### Usage: ###
-Depends on [jsonrpc](http://json-rpc.org/).
-
- spendfrom.py --from=FROMADDRESS1[,FROMADDRESS2] --to=TOADDRESS --amount=amount \
- --fee=fee --datadir=/path/to/.bitcoin --testnet --dry_run
-
-With no arguments, outputs a list of amounts associated with addresses.
-
-With arguments, sends coins received by the `FROMADDRESS` addresses to the `TOADDRESS`.
-
-### Notes ###
-
-- You may explicitly specify how much fee to pay (a fee more than 1% of the amount
-will fail, though, to prevent bitcoin-losing accidents). Spendfrom may fail if
-it thinks the transaction would never be confirmed (if the amount being sent is
-too small, or if the transaction is too many bytes for the fee).
-
-- If a change output needs to be created, the change will be sent to the last
-`FROMADDRESS` (if you specify just one `FROMADDRESS`, change will go back to it).
-
-- If `--datadir` is not specified, the default datadir is used.
-
-- The `--dry_run` option will just create and sign the transaction and print
-the transaction data (as hexadecimal), instead of broadcasting it.
-
-- If the transaction is created and broadcast successfully, a transaction id
-is printed.
-
-- If this was a tool for end-users and not programmers, it would have much friendlier
-error-handling.
diff --git a/contrib/spendfrom/setup.py b/contrib/spendfrom/setup.py
deleted file mode 100644
index 01b9768a5b..0000000000
--- a/contrib/spendfrom/setup.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from distutils.core import setup
-setup(name='btcspendfrom',
- version='1.0',
- description='Command-line utility for bitcoin "coin control"',
- author='Gavin Andresen',
- author_email='gavin@bitcoinfoundation.org',
- requires=['jsonrpc'],
- scripts=['spendfrom.py'],
- )
diff --git a/contrib/spendfrom/spendfrom.py b/contrib/spendfrom/spendfrom.py
deleted file mode 100755
index 72ee0425eb..0000000000
--- a/contrib/spendfrom/spendfrom.py
+++ /dev/null
@@ -1,267 +0,0 @@
-#!/usr/bin/env python
-#
-# Use the raw transactions API to spend bitcoins received on particular addresses,
-# and send any change back to that same address.
-#
-# Example usage:
-# spendfrom.py # Lists available funds
-# spendfrom.py --from=ADDRESS --to=ADDRESS --amount=11.00
-#
-# Assumes it will talk to a bitcoind or Bitcoin-Qt running
-# on localhost.
-#
-# Depends on jsonrpc
-#
-
-from decimal import *
-import getpass
-import math
-import os
-import os.path
-import platform
-import sys
-import time
-from jsonrpc import ServiceProxy, json
-
-BASE_FEE=Decimal("0.001")
-
-def check_json_precision():
- """Make sure json library being used does not lose precision converting BTC values"""
- n = Decimal("20000000.00000003")
- satoshis = int(json.loads(json.dumps(float(n)))*1.0e8)
- if satoshis != 2000000000000003:
- raise RuntimeError("JSON encode/decode loses precision")
-
-def determine_db_dir():
- """Return the default location of the bitcoin data directory"""
- if platform.system() == "Darwin":
- return os.path.expanduser("~/Library/Application Support/Bitcoin/")
- elif platform.system() == "Windows":
- return os.path.join(os.environ['APPDATA'], "Bitcoin")
- return os.path.expanduser("~/.bitcoin")
-
-def read_bitcoin_config(dbdir):
- """Read the bitcoin.conf file from dbdir, returns dictionary of settings"""
- from ConfigParser import SafeConfigParser
-
- class FakeSecHead(object):
- def __init__(self, fp):
- self.fp = fp
- self.sechead = '[all]\n'
- def readline(self):
- if self.sechead:
- try: return self.sechead
- finally: self.sechead = None
- else:
- s = self.fp.readline()
- if s.find('#') != -1:
- s = s[0:s.find('#')].strip() +"\n"
- return s
-
- config_parser = SafeConfigParser()
- config_parser.readfp(FakeSecHead(open(os.path.join(dbdir, "bitcoin.conf"))))
- return dict(config_parser.items("all"))
-
-def connect_JSON(config):
- """Connect to a bitcoin JSON-RPC server"""
- testnet = config.get('testnet', '0')
- testnet = (int(testnet) > 0) # 0/1 in config file, convert to True/False
- if not 'rpcport' in config:
- config['rpcport'] = 18332 if testnet else 8332
- connect = "http://%s:%s@127.0.0.1:%s"%(config['rpcuser'], config['rpcpassword'], config['rpcport'])
- try:
- result = ServiceProxy(connect)
- # ServiceProxy is lazy-connect, so send an RPC command mostly to catch connection errors,
- # but also make sure the bitcoind we're talking to is/isn't testnet:
- if result.getmininginfo()['testnet'] != testnet:
- sys.stderr.write("RPC server at "+connect+" testnet setting mismatch\n")
- sys.exit(1)
- return result
- except:
- sys.stderr.write("Error connecting to RPC server at "+connect+"\n")
- sys.exit(1)
-
-def unlock_wallet(bitcoind):
- info = bitcoind.getinfo()
- if 'unlocked_until' not in info:
- return True # wallet is not encrypted
- t = int(info['unlocked_until'])
- if t <= time.time():
- try:
- passphrase = getpass.getpass("Wallet is locked; enter passphrase: ")
- bitcoind.walletpassphrase(passphrase, 5)
- except:
- sys.stderr.write("Wrong passphrase\n")
-
- info = bitcoind.getinfo()
- return int(info['unlocked_until']) > time.time()
-
-def list_available(bitcoind):
- address_summary = dict()
-
- address_to_account = dict()
- for info in bitcoind.listreceivedbyaddress(0):
- address_to_account[info["address"]] = info["account"]
-
- unspent = bitcoind.listunspent(0)
- for output in unspent:
- # listunspent doesn't give addresses, so:
- rawtx = bitcoind.getrawtransaction(output['txid'], 1)
- vout = rawtx["vout"][output['vout']]
- pk = vout["scriptPubKey"]
-
- # This code only deals with ordinary pay-to-bitcoin-address
- # or pay-to-script-hash outputs right now; anything exotic is ignored.
- if pk["type"] != "pubkeyhash" and pk["type"] != "scripthash":
- continue
-
- address = pk["addresses"][0]
- if address in address_summary:
- address_summary[address]["total"] += vout["value"]
- address_summary[address]["outputs"].append(output)
- else:
- address_summary[address] = {
- "total" : vout["value"],
- "outputs" : [output],
- "account" : address_to_account.get(address, "")
- }
-
- return address_summary
-
-def select_coins(needed, inputs):
- # Feel free to improve this, this is good enough for my simple needs:
- outputs = []
- have = Decimal("0.0")
- n = 0
- while have < needed and n < len(inputs):
- outputs.append({ "txid":inputs[n]["txid"], "vout":inputs[n]["vout"]})
- have += inputs[n]["amount"]
- n += 1
- return (outputs, have-needed)
-
-def create_tx(bitcoind, fromaddresses, toaddress, amount, fee):
- all_coins = list_available(bitcoind)
-
- total_available = Decimal("0.0")
- needed = amount+fee
- potential_inputs = []
- for addr in fromaddresses:
- if addr not in all_coins:
- continue
- potential_inputs.extend(all_coins[addr]["outputs"])
- total_available += all_coins[addr]["total"]
-
- if total_available < needed:
- sys.stderr.write("Error, only %f BTC available, need %f\n"%(total_available, needed));
- sys.exit(1)
-
- #
- # Note:
- # Python's json/jsonrpc modules have inconsistent support for Decimal numbers.
- # Instead of wrestling with getting json.dumps() (used by jsonrpc) to encode
- # Decimals, I'm casting amounts to float before sending them to bitcoind.
- #
- outputs = { toaddress : float(amount) }
- (inputs, change_amount) = select_coins(needed, potential_inputs)
- if change_amount > BASE_FEE: # don't bother with zero or tiny change
- change_address = fromaddresses[-1]
- if change_address in outputs:
- outputs[change_address] += float(change_amount)
- else:
- outputs[change_address] = float(change_amount)
-
- rawtx = bitcoind.createrawtransaction(inputs, outputs)
- signed_rawtx = bitcoind.signrawtransaction(rawtx)
- if not signed_rawtx["complete"]:
- sys.stderr.write("signrawtransaction failed\n")
- sys.exit(1)
- txdata = signed_rawtx["hex"]
-
- return txdata
-
-def compute_amount_in(bitcoind, txinfo):
- result = Decimal("0.0")
- for vin in txinfo['vin']:
- in_info = bitcoind.getrawtransaction(vin['txid'], 1)
- vout = in_info['vout'][vin['vout']]
- result = result + vout['value']
- return result
-
-def compute_amount_out(txinfo):
- result = Decimal("0.0")
- for vout in txinfo['vout']:
- result = result + vout['value']
- return result
-
-def sanity_test_fee(bitcoind, txdata_hex, max_fee):
- class FeeError(RuntimeError):
- pass
- try:
- txinfo = bitcoind.decoderawtransaction(txdata_hex)
- total_in = compute_amount_in(bitcoind, txinfo)
- total_out = compute_amount_out(txinfo)
- if total_in-total_out > max_fee:
- raise FeeError("Rejecting transaction, unreasonable fee of "+str(total_in-total_out))
-
- tx_size = len(txdata_hex)/2
- kb = tx_size/1000 # integer division rounds down
- if kb > 1 and fee < BASE_FEE:
- raise FeeError("Rejecting no-fee transaction, larger than 1000 bytes")
- if total_in < 0.01 and fee < BASE_FEE:
- raise FeeError("Rejecting no-fee, tiny-amount transaction")
- # Exercise for the reader: compute transaction priority, and
- # warn if this is a very-low-priority transaction
-
- except FeeError as err:
- sys.stderr.write((str(err)+"\n"))
- sys.exit(1)
-
-def main():
- import optparse
-
- parser = optparse.OptionParser(usage="%prog [options]")
- parser.add_option("--from", dest="fromaddresses", default=None,
- help="addresses to get bitcoins from")
- parser.add_option("--to", dest="to", default=None,
- help="address to get send bitcoins to")
- parser.add_option("--amount", dest="amount", default=None,
- help="amount to send")
- parser.add_option("--fee", dest="fee", default="0.0",
- help="fee to include")
- parser.add_option("--datadir", dest="datadir", default=determine_db_dir(),
- help="location of bitcoin.conf file with RPC username/password (default: %default)")
- parser.add_option("--testnet", dest="testnet", default=False, action="store_true",
- help="Use the test network")
- parser.add_option("--dry_run", dest="dry_run", default=False, action="store_true",
- help="Don't broadcast the transaction, just create and print the transaction data")
-
- (options, args) = parser.parse_args()
-
- check_json_precision()
- config = read_bitcoin_config(options.datadir)
- if options.testnet: config['testnet'] = True
- bitcoind = connect_JSON(config)
-
- if options.amount is None:
- address_summary = list_available(bitcoind)
- for address,info in address_summary.iteritems():
- n_transactions = len(info['outputs'])
- if n_transactions > 1:
- print("%s %.8f %s (%d transactions)"%(address, info['total'], info['account'], n_transactions))
- else:
- print("%s %.8f %s"%(address, info['total'], info['account']))
- else:
- fee = Decimal(options.fee)
- amount = Decimal(options.amount)
- while unlock_wallet(bitcoind) == False:
- pass # Keep asking for passphrase until they get it right
- txdata = create_tx(bitcoind, options.fromaddresses.split(","), options.to, amount, fee)
- sanity_test_fee(bitcoind, txdata, amount*Decimal("0.01"))
- if options.dry_run:
- print(txdata)
- else:
- txid = bitcoind.sendrawtransaction(txdata)
- print(txid)
-
-if __name__ == '__main__':
- main()
diff --git a/contrib/testgen/base58.py b/contrib/testgen/base58.py
index b716495145..0d09692b36 100644
--- a/contrib/testgen/base58.py
+++ b/contrib/testgen/base58.py
@@ -1,3 +1,6 @@
+# Copyright (c) 2012-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.
'''
Bitcoin base58 encoding and decoding.
@@ -81,7 +84,6 @@ def b58decode_chk(v):
result = b58decode(v)
if result is None:
return None
- h3 = checksum(result[:-4])
if result[-4:] == checksum(result[:-4]):
return result[:-4]
else:
diff --git a/contrib/testgen/gen_base58_test_vectors.py b/contrib/testgen/gen_base58_test_vectors.py
index 1813436953..86366eb8e3 100755
--- a/contrib/testgen/gen_base58_test_vectors.py
+++ b/contrib/testgen/gen_base58_test_vectors.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python
+# Copyright (c) 2012-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.
'''
Generate valid and invalid base58 address and private key test vectors.
@@ -10,7 +13,7 @@ Usage:
# Released under MIT License
import os
from itertools import islice
-from base58 import b58encode, b58decode, b58encode_chk, b58decode_chk, b58chars
+from base58 import b58encode_chk, b58decode_chk, b58chars
import random
from binascii import b2a_hex
@@ -42,7 +45,6 @@ def is_valid(v):
result = b58decode_chk(v)
if result is None:
return False
- valid = False
for template in templates:
prefix = str(bytearray(template[0]))
suffix = str(bytearray(template[2]))
diff --git a/contrib/tidy_datadir.sh b/contrib/tidy_datadir.sh
index 5d6d826444..8960f8811d 100755
--- a/contrib/tidy_datadir.sh
+++ b/contrib/tidy_datadir.sh
@@ -1,4 +1,7 @@
#!/bin/bash
+# Copyright (c) 2013 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
if [ -d "$1" ]; then
cd "$1"
diff --git a/contrib/verify-commits/allow-revsig-commits b/contrib/verify-commits/allow-revsig-commits
index e69de29bb2..f0088cdca4 100644
--- a/contrib/verify-commits/allow-revsig-commits
+++ b/contrib/verify-commits/allow-revsig-commits
@@ -0,0 +1,104 @@
+a06ede9a138d0fb86b0de17c42b936d9fe6e2158
+923dc447eaa8e017985b2afbbb12dd1283fbea0e
+71148b8947fe8b4d756822420a7f31c380159425
+6696b4635ceb9b47aaa63244bff9032fa7b08354
+812714fd80e96e28cd288c553c83838cecbfc2d9
+8a445c5651edb9a1f51497055b7ddf4402be9188
+e126d0c12ca66278d9e7b12187c5ff4fc02a7e6c
+3908fc4728059719bed0e1c7b1c8b388c2d4a8da
+8b66bf74e2a349e71eaa183af81fa63eaee76ad2
+05950427d310654774031764a7141a1a4fd9c6e4
+07fd147b9f12e9205afd66a624edce357977d615
+12e31127948fa4bb01c3bddc1b8c85b432f7465b
+8c87f175d335e9d9e93f987d871ae9f05f6a10a7
+46b249e578e8a3dfbe85bc7253a12e82ef4b658b
+a55716abe5662ec74c2f8af93023f1e7cca901fc
+f646275b90b1de93bc62b4c4d045d75ac0b96eee
+c252685aa5867631e9a5ef07ccae7c7c25cae8ff
+a7d55c93385359952d85decd5037843ac70ba3d4
+7dac1e5e9e887f5f6ff146e812a05bd3bf281eae
+2a524b8e8fe69ef487fd8ea1b4f7a03f473ed201
+ce5c1f4acae43477989cdf9a82ed33703919cda2
+2db4cbcc437f51f5dac82cc4de46f383b92e6f11
+7aa700424cbda387536373d8dfec88aee43f950e
+b99a093afed880f23fb279c443cc6ae5e379cc43
+b83264d9c7a8ddb79f64bd9540caddc8632ef31f
+57e337d40e94ba33d8cd265c134d6ef857b32b59
+a1dcf2e1087beaf3981739fd2bb74f35ecad630a
+d38b0d7a6b6056cba26999b702815775e2437d87
+815640ec6af9a38d6a2da4a4400056e2f4105080
+09c4fd157c5b88df2d97fad4826c79b094db90c9
+2efcfa5acfacb958973d9e8125e1d81f102e2dfd
+dc6dee41f7cf2ba93fcd0fea7c157e4b2775d439
+ad826b3df9f763b49f1e3e3d50c4efdd438c7547
+c1a52276848d8caa9a9789dff176408c1aa6b1ed
+3bf06e9bac57b5b5a746677b75e297a7b154bdbd
+72ae6f8cf0224370e8121d6769b21e612ca15d6f
+a143b88dbd4971ecfdd1d39a494489c8f2db0344
+76fec09d878d6dbf214bdb6228d480bd9195db4c
+93566e0c37c5ae104095474fea89f00dcb40f551
+407d9232ef5cb1ebf6cff21f3d13e07ea4158eeb
+9346f8429957e356d21c665bab59fe45bcf1f74e
+6eeac6e30d65f9a972067c1ea8c49978c8e631ac
+dc6b9406bdfab2af8c86cb080cb3e6cf8f2385d8
+9f554e03ebe5701c1b75ff03b3d6152095c0cad3
+05009935f9ac070197113954d680bc2c9150b9b3
+508404de98a8a5435f52916cef8f328e82651961
+ed0cc50afed146c27f6d8129c683c225fb940093
+6429cfa8a70308241c576aeb92ffe3db5203b2ef
+6898213409811b140843c3d89af43328c3b22fad
+5b2ea29cf4fd298346437bb16a54407f8c1f9dca
+e2a1a1ee895149c544d4ae295466611f0cec3094
+e82fb872ff5cc8fd22d43327c1ee3e755f61c562
+19b0f33de0efd9da788e8e4f3fdc2a9e159abdb1
+89de1538ce1f8c00f80e8d11f43e1b77e24d7dea
+de07fdcf77e97b8613091285e4d0a734f5de7492
+01680195f8aa586c55c44767397380def3a23b54
+05e1c85fb687c82ae477c72d4a7e2d6b0c692167
+c072b8fd95cd4fa84f08189a0cd8b173ea2dbb8e
+9a0ed08b40b15ae2b791aa8549b53e69934b4ea7
+53f8f226bd1d627c4a6dec5862a1d4ea5a933e45
+9d0f43b7ca7241d8a018fd35dd3bc01555235ec6
+f12d2b5a8ac397e4bcaefcc19898f8ff5705dea5
+8250de13587ed05ca45df3e12c5dc9bcb1500e2c
+d727f77e390426e9e463336bda08d50c451c7086
+484312bda2d43e3ea60047be076332299463adf8
+c7e05b35ab0a791c7a8e2d863e716fdec6f3f671
+b9c1cd81848da9de1baf9c2f29c19c50e549de13
+8ea7d31e384975019733b5778feabbd9955c79d8
+f798b891bcecea9548eedacae70eeb9906c1ddbf
+ebefe7a00b46579cdd1e033a8c7fd8ce9aa578e4
+ad087638ee4864d6244ec9381ff764bfa6ee5086
+66db2d62d59817320c9182fc18e75a93b76828ea
+7ce9ac5c83b1844a518ef2e12e87aae3cacdfe58
+4286f43025149cf44207c3ad98e4a1f068520ada
+cd0c5135ab2291aaa5410ac919bad3fc87249a4a
+66ed450d771a8fc01c159a8402648ebd1c35eb4c
+a82f03393a32842d49236e8666ee57805ca701f8
+f972b04d63eb8af79ff3cec1dc561ed13dfa6053
+ec45cc5e27668171b55271b0c735194c70e7da41
+715e9fd7454f7a48d7adba7d42f662c20a3e3367
+2e0a99037dcc35bc63ba0d54371bc678af737c8e
+7fa8d758598407f3bf0beb0118dc122ea5340736
+6a22373771edbc3c7513cacb9355f880c73c2cbf
+b89ef131147f71a96152a7b5c4374266cdf539b2
+01d8359983e2f77b5118fede3ffa947072c666c8
+58f0c929a3d70a4bff79cc200f1c186f71ef1675
+950be19727a581970591d8f8138dfe4725750382
+425278d17bd0edf8a3a7cc81e55016f7fd8e7726
+c028c7b7557da2baff7af8840108e8be4db8e0c6
+47a7cfb0aa2498f6801026d258a59f9de48f60b0
+f6b7df3155ddb4cedfbcf5d3eb3383d4614b3a85
+d72098038f3b55a714ed8adb34fab547b15eb0d5
+c49c825bd9f4764536b45df5a684d97173673fc7
+33799afe83eec4200ff140e9bf5eae83701a4d7f
+5c3f8ddcaa1164079105c452429fccf8127b01b6
+1f01443567b03ac75a91c810f1733f5c21b5699d
+b3e42b6d02e8d19658a9135e427ebceab5367779
+69b3a6dd9d9a0adf5506c8b9fde42187356bd4a8
+bafd075c5e6a1088ef0f1aa0b0b224e026a3d3e0
+7daa3adb242d9c8728fdb15c6af6596aaad5502f
+514993554c370f4cf30a109ac28d5d64893dbf0a
+c8d2473e6cb042e7275a10c49d3f6a4a91bf0166
+386f4385ab04b0b2c3d47bddc0dc0f2de7354964
+9f33dba05c01ecc5c56eb1284ab7d64d42f55171
diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh
index 375d711725..b01e2a6d39 100755
--- a/contrib/verify-commits/gpg.sh
+++ b/contrib/verify-commits/gpg.sh
@@ -1,24 +1,50 @@
#!/bin/sh
+# Copyright (c) 2014-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.
+
INPUT=$(cat /dev/stdin)
VALID=false
REVSIG=false
IFS='
'
-for LINE in $(echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null); do
+if [ "$BITCOIN_VERIFY_COMMITS_ALLOW_SHA1" = 1 ]; then
+ GPG_RES="$(echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)"
+else
+ # Note how we've disabled SHA1 with the --weak-digest option, disabling
+ # signatures - including selfsigs - that use SHA1. While you might think that
+ # collision attacks shouldn't be an issue as they'd be an attack on yourself,
+ # in fact because what's being signed is a commit object that's
+ # semi-deterministically generated by untrusted input (the pull-req) in theory
+ # an attacker could construct a pull-req that results in a commit object that
+ # they've created a collision for. Not the most likely attack, but preventing
+ # it is pretty easy so we do so as a "belt-and-suspenders" measure.
+ GPG_RES=""
+ for LINE in "$(gpg --version)"; do
+ case "$LINE" in
+ "gpg (GnuPG) 1.4.1"*|"gpg (GnuPG) 2.0."*)
+ echo "Please upgrade to at least gpg 2.1.10 to check for weak signatures" > /dev/stderr
+ GPG_RES="$(echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)"
+ ;;
+ # We assume if you're running 2.1+, you're probably running 2.1.10+
+ # gpg will fail otherwise
+ # We assume if you're running 1.X, it is either 1.4.1X or 1.4.20+
+ # gpg will fail otherwise
+ esac
+ done
+ [ "$GPG_RES" = "" ] && GPG_RES="$(echo "$INPUT" | gpg --trust-model always --weak-digest sha1 "$@" 2>/dev/null)"
+fi
+for LINE in $(echo "$GPG_RES"); do
case "$LINE" in
"[GNUPG:] VALIDSIG "*)
while read KEY; do
- case "$LINE" in "[GNUPG:] VALIDSIG $KEY "*) VALID=true;; esac
+ [ "${LINE#?GNUPG:? VALIDSIG * * * * * * * * * }" = "$KEY" ] && VALID=true
done < ./contrib/verify-commits/trusted-keys
;;
"[GNUPG:] REVKEYSIG "*)
[ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1
- while read KEY; do
- case "$LINE" in "[GNUPG:] REVKEYSIG ${KEY#????????????????????????} "*)
- REVSIG=true
- GOODREVSIG="[GNUPG:] GOODSIG ${KEY#????????????????????????} "
- esac
- done < ./contrib/verify-commits/trusted-keys
+ REVSIG=true
+ GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}"
;;
esac
done
@@ -26,7 +52,7 @@ if ! $VALID; then
exit 1
fi
if $VALID && $REVSIG; then
- echo "$INPUT" | gpg --trust-model always "$@" | grep "\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)" 2>/dev/null
+ echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null | grep "\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)"
echo "$GOODREVSIG"
else
echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null
diff --git a/contrib/verify-commits/pre-push-hook.sh b/contrib/verify-commits/pre-push-hook.sh
index c57222818a..c21febb9e9 100755
--- a/contrib/verify-commits/pre-push-hook.sh
+++ b/contrib/verify-commits/pre-push-hook.sh
@@ -1,4 +1,8 @@
#!/bin/bash
+# Copyright (c) 2014-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.
+
if ! [[ "$2" =~ ^(git@)?(www.)?github.com(:|/)bitcoin/bitcoin(.git)?$ ]]; then
exit 0
fi
diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys
index 75242c2a97..5610692616 100644
--- a/contrib/verify-commits/trusted-keys
+++ b/contrib/verify-commits/trusted-keys
@@ -1,4 +1,4 @@
71A3B16735405025D447E8F274810B012346C9A6
-3F1888C6DCA92A6499C4911FDBA1A67379A1A931
+133EAC179436F14A5CF1B794860FEB804E669320
32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC
-FE09B823E6D83A3BC7983EAA2D7F2372E50FE137
+B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B
diff --git a/contrib/verify-commits/trusted-sha512-root-commit b/contrib/verify-commits/trusted-sha512-root-commit
new file mode 100644
index 0000000000..7d41f90ad7
--- /dev/null
+++ b/contrib/verify-commits/trusted-sha512-root-commit
@@ -0,0 +1 @@
+309bf16257b2395ce502017be627186b749ee749
diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh
index 5219331e2e..74b7f38375 100755
--- a/contrib/verify-commits/verify-commits.sh
+++ b/contrib/verify-commits/verify-commits.sh
@@ -1,58 +1,132 @@
#!/bin/sh
-# Not technically POSIX-compliant due to use of "local", but almost every
-# shell anyone uses today supports it, so its probably fine
+# Copyright (c) 2014-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.
DIR=$(dirname "$0")
[ "/${DIR#/}" != "$DIR" ] && DIR=$(dirname "$(pwd)/$0")
+echo "Using verify-commits data from ${DIR}"
+
VERIFIED_ROOT=$(cat "${DIR}/trusted-git-root")
+VERIFIED_SHA512_ROOT=$(cat "${DIR}/trusted-sha512-root-commit")
REVSIG_ALLOWED=$(cat "${DIR}/allow-revsig-commits")
HAVE_FAILED=false
-IS_SIGNED () {
- if [ $1 = $VERIFIED_ROOT ]; then
- return 0;
+
+HAVE_GNU_SHA512=1
+[ ! -x "$(which sha512sum)" ] && HAVE_GNU_SHA512=0
+
+if [ x"$1" = "x" ]; then
+ CURRENT_COMMIT="HEAD"
+else
+ CURRENT_COMMIT="$1"
+fi
+
+if [ "${CURRENT_COMMIT#* }" != "$CURRENT_COMMIT" ]; then
+ echo "Commit must not contain spaces?" > /dev/stderr
+ exit 1
+fi
+
+VERIFY_TREE=0
+if [ x"$2" = "x--tree-checks" ]; then
+ VERIFY_TREE=1
+fi
+
+NO_SHA1=1
+PREV_COMMIT=""
+
+while true; do
+ if [ "$CURRENT_COMMIT" = $VERIFIED_ROOT ]; then
+ echo "There is a valid path from "$CURRENT_COMMIT" to $VERIFIED_ROOT where all commits are signed!"
+ exit 0;
+ fi
+
+ if [ "$CURRENT_COMMIT" = $VERIFIED_SHA512_ROOT ]; then
+ if [ "$VERIFY_TREE" = "1" ]; then
+ echo "All Tree-SHA512s matched up to $VERIFIED_SHA512_ROOT" > /dev/stderr
+ fi
+ VERIFY_TREE=0
+ NO_SHA1=0
fi
- if [ "${REVSIG_ALLOWED#*$1}" != "$REVSIG_ALLOWED" ]; then
+
+ if [ "$NO_SHA1" = "1" ]; then
+ export BITCOIN_VERIFY_COMMITS_ALLOW_SHA1=0
+ else
+ export BITCOIN_VERIFY_COMMITS_ALLOW_SHA1=1
+ fi
+
+ if [ "${REVSIG_ALLOWED#*$CURRENT_COMMIT}" != "$REVSIG_ALLOWED" ]; then
export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=1
else
export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=0
fi
- if ! git -c "gpg.program=${DIR}/gpg.sh" verify-commit $1 > /dev/null 2>&1; then
- return 1;
- fi
- local PARENTS
- PARENTS=$(git show -s --format=format:%P $1)
- for PARENT in $PARENTS; do
- if IS_SIGNED $PARENT > /dev/null; then
- return 0;
+
+ if ! git -c "gpg.program=${DIR}/gpg.sh" verify-commit "$CURRENT_COMMIT" > /dev/null; then
+ if [ "$PREV_COMMIT" != "" ]; then
+ echo "No parent of $PREV_COMMIT was signed with a trusted key!" > /dev/stderr
+ echo "Parents are:" > /dev/stderr
+ PARENTS=$(git show -s --format=format:%P $PREV_COMMIT)
+ for PARENT in $PARENTS; do
+ git show -s $PARENT > /dev/stderr
+ done
+ else
+ echo "$CURRENT_COMMIT was not signed with a trusted key!" > /dev/stderr
fi
- done
- if ! "$HAVE_FAILED"; then
- echo "No parent of $1 was signed with a trusted key!" > /dev/stderr
- echo "Parents are:" > /dev/stderr
- for PARENT in $PARENTS; do
- git show -s $PARENT > /dev/stderr
- done
- HAVE_FAILED=true
+ exit 1
fi
- return 1;
-}
-if [ x"$1" = "x" ]; then
- TEST_COMMIT="HEAD"
-else
- TEST_COMMIT="$1"
-fi
+ # We always verify the top of the tree
+ if [ "$VERIFY_TREE" = 1 -o "$PREV_COMMIT" = "" ]; then
+ IFS_CACHE="$IFS"
+ IFS='
+'
+ for LINE in $(git ls-tree --full-tree -r "$CURRENT_COMMIT"); do
+ case "$LINE" in
+ "12"*)
+ echo "Repo contains symlinks" > /dev/stderr
+ IFS="$IFS_CACHE"
+ exit 1
+ ;;
+ esac
+ done
+ IFS="$IFS_CACHE"
-IS_SIGNED "$TEST_COMMIT"
-RES=$?
-if [ "$RES" = 1 ]; then
- if ! "$HAVE_FAILED"; then
- echo "$TEST_COMMIT was not signed with a trusted key!"
+ FILE_HASHES=""
+ for FILE in $(git ls-tree --full-tree -r --name-only "$CURRENT_COMMIT" | LC_ALL=C sort); do
+ if [ "$HAVE_GNU_SHA512" = 1 ]; then
+ HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | sha512sum | { read FIRST OTHER; echo $FIRST; } )
+ else
+ HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | shasum -a 512 | { read FIRST OTHER; echo $FIRST; } )
+ fi
+ [ "$FILE_HASHES" != "" ] && FILE_HASHES="$FILE_HASHES"'
+'
+ FILE_HASHES="$FILE_HASHES$HASH $FILE"
+ done
+
+ if [ "$HAVE_GNU_SHA512" = 1 ]; then
+ TREE_HASH="$(echo "$FILE_HASHES" | sha512sum)"
+ else
+ TREE_HASH="$(echo "$FILE_HASHES" | shasum -a 512)"
+ fi
+ HASH_MATCHES=0
+ MSG="$(git show -s --format=format:%B "$CURRENT_COMMIT" | tail -n1)"
+
+ case "$MSG -" in
+ "Tree-SHA512: $TREE_HASH")
+ HASH_MATCHES=1;;
+ esac
+
+ if [ "$HASH_MATCHES" = "0" ]; then
+ echo "Tree-SHA512 did not match for commit $CURRENT_COMMIT" > /dev/stderr
+ exit 1
+ fi
fi
-else
- echo "There is a valid path from $TEST_COMMIT to $VERIFIED_ROOT where all commits are signed!"
-fi
-exit $RES
+ PARENTS=$(git show -s --format=format:%P "$CURRENT_COMMIT")
+ for PARENT in $PARENTS; do
+ PREV_COMMIT="$CURRENT_COMMIT"
+ CURRENT_COMMIT="$PARENT"
+ break
+ done
+done
diff --git a/contrib/verifybinaries/README.md b/contrib/verifybinaries/README.md
index 8970f3daa4..ed3e14fb6c 100644
--- a/contrib/verifybinaries/README.md
+++ b/contrib/verifybinaries/README.md
@@ -1,13 +1,33 @@
### Verify Binaries
+
+#### Preparation:
+
+Make sure you obtain the proper release signing key and verify the fingerprint with several independent sources.
+
+```sh
+$ gpg --fingerprint "Bitcoin Core binary release signing key"
+pub 4096R/36C2E964 2015-06-24 [expires: 2017-02-13]
+ Key fingerprint = 01EA 5486 DE18 A882 D4C2 6845 90C8 019E 36C2 E964
+uid Wladimir J. van der Laan (Bitcoin Core binary release signing key) <laanwj@gmail.com>
+```
+
+#### Usage:
+
This script attempts to download the signature file `SHA256SUMS.asc` from https://bitcoin.org.
It first checks if the signature passes, and then downloads the files specified in the file, and checks if the hashes of these files match those that are specified in the signature file.
The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2.
-Usage:
```sh
./verify.sh bitcoin-core-0.11.2
./verify.sh bitcoin-core-0.12.0
+./verify.sh bitcoin-core-0.13.0-rc3
+```
+
+If you do not want to keep the downloaded binaries, specify anything as the second parameter.
+
+```sh
+./verify.sh bitcoin-core-0.13.0 delete
```
diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh
index 657c3bd33c..e20770c96a 100755
--- a/contrib/verifybinaries/verify.sh
+++ b/contrib/verifybinaries/verify.sh
@@ -1,4 +1,7 @@
#!/bin/bash
+# Copyright (c) 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.
### This script attempts to download the signature file SHA256SUMS.asc from bitcoin.org
### It first checks if the signature passes, and then downloads the files specified in
@@ -14,11 +17,11 @@ function clean_up {
done
}
-WORKINGDIR="/tmp/bitcoin"
+WORKINGDIR="/tmp/bitcoin_verify_binaries"
TMPFILE="hashes.tmp"
SIGNATUREFILENAME="SHA256SUMS.asc"
-RCSUBDIR="test/"
+RCSUBDIR="test"
BASEDIR="https://bitcoin.org/bin/"
VERSIONPREFIX="bitcoin-core-"
RCVERSIONSTRING="rc"
@@ -43,7 +46,7 @@ if [ -n "$1" ]; then
# and simultaneously add RCSUBDIR to BASEDIR, where we will look for SIGNATUREFILENAME
if [[ $VERSION == *"$RCVERSIONSTRING"* ]]; then
BASEDIR="$BASEDIR${VERSION/%-$RCVERSIONSTRING*}/"
- BASEDIR="$BASEDIR$RCSUBDIR"
+ BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSIONSTRING${VERSION: -1}/"
else
BASEDIR="$BASEDIR$VERSION/"
fi
@@ -93,7 +96,7 @@ fi
FILES=$(awk '{print $2}' "$TMPFILE")
#and download these one by one
-for file in in $FILES
+for file in $FILES
do
wget --quiet -N "$BASEDIR$file"
done
@@ -108,11 +111,16 @@ if [ $? -eq 1 ]; then
exit 1
elif [ $? -gt 1 ]; then
echo "Error executing 'diff'"
- exit 2
+ exit 2
fi
-#everything matches! clean up the mess
-clean_up $FILES $SIGNATUREFILENAME $TMPFILE
+if [ -n "$2" ]; then
+ echo "Clean up the binaries"
+ clean_up $FILES $SIGNATUREFILENAME $TMPFILE
+else
+ echo "Keep the binaries in $WORKINGDIR"
+ clean_up $TMPFILE
+fi
echo -e "Verified hashes of \n$FILES"
diff --git a/contrib/windeploy/detached-sig-create.sh b/contrib/windeploy/detached-sig-create.sh
new file mode 100755
index 0000000000..bf4978d143
--- /dev/null
+++ b/contrib/windeploy/detached-sig-create.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Copyright (c) 2014-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.
+
+if [ -z "$OSSLSIGNCODE" ]; then
+ OSSLSIGNCODE=osslsigncode
+fi
+
+if [ ! -n "$1" ]; then
+ echo "usage: $0 <osslcodesign args>"
+ echo "example: $0 -key codesign.key"
+ exit 1
+fi
+
+OUT=signature-win.tar.gz
+SRCDIR=unsigned
+WORKDIR=./.tmp
+OUTDIR="${WORKDIR}/out"
+OUTSUBDIR="${OUTDIR}/win"
+TIMESERVER=http://timestamp.comodoca.com
+CERTFILE="win-codesign.cert"
+
+mkdir -p "${OUTSUBDIR}"
+basename -a `ls -1 "${SRCDIR}"/*-unsigned.exe` | while read UNSIGNED; do
+ echo Signing "${UNSIGNED}"
+ "${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@"
+ "${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${UNSIGNED}" -out "${OUTSUBDIR}/${UNSIGNED}.pem" && rm "${WORKDIR}/${UNSIGNED}"
+done
+
+rm -f "${OUT}"
+tar -C "${OUTDIR}" -czf "${OUT}" .
+rm -rf "${WORKDIR}"
+echo "Created ${OUT}"
diff --git a/contrib/windeploy/win-codesign.cert b/contrib/windeploy/win-codesign.cert
new file mode 100644
index 0000000000..200b30a3f0
--- /dev/null
+++ b/contrib/windeploy/win-codesign.cert
@@ -0,0 +1,99 @@
+-----BEGIN CERTIFICATE-----
+MIIFTTCCBDWgAwIBAgIRALlW05RLwG2hMQMX5d/o5J8wDQYJKoZIhvcNAQELBQAw
+fTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxIzAhBgNV
+BAMTGkNPTU9ETyBSU0EgQ29kZSBTaWduaW5nIENBMB4XDTE2MDIwMzAwMDAwMFoX
+DTE5MDMwNTIzNTk1OVowgbUxCzAJBgNVBAYTAlVTMQ4wDAYDVQQRDAU5ODEwNDEL
+MAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAkMB1N0ZSAzMDAx
+FzAVBgNVBAkMDjcxIENvbHVtYmlhIFN0MSUwIwYDVQQKDBxUaGUgQml0Y29pbiBG
+b3VuZGF0aW9uLCBJbmMuMSUwIwYDVQQDDBxUaGUgQml0Y29pbiBGb3VuZGF0aW9u
+LCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw37Vrv9Gbku0
++kuV0t89TuyxtAcmT7QE4GcwESKKjmkxfzD9a0qlhqk8GfQ+fw4DHNN+nLKNv7xB
+bk6aS7J2v2DcXkOjrP99P9jqgTkp7MC04VtG3OqVRGB+gum0pptRovYZUQXIdkY7
+GJOok/NDagwKiiUe2V2meZ7UctsZNvYeilQdTgKIIhrMB9NowCOhT8ocVL4Ki55/
+l7hukJn3fueCM3fHTwY2/1gaGsOHoCkFRsD7vokjAVpiY+8rUgvHjb0gxgojiVGd
+6a6/F5XJwKJacvUyN4Hfc2K5lRMQjTTmo4aWNWIa0iJ3TK9BHpdSLJBqerMPvmnM
+kkapS+ZTNQIDAQABo4IBjTCCAYkwHwYDVR0jBBgwFoAUKZFg/4pN+uv5pmq4z/nm
+S71JzhIwHQYDVR0OBBYEFONpQ+cV82URVe+V8G57377KxxexMA4GA1UdDwEB/wQE
+AwIHgDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBEGCWCGSAGG
++EIBAQQEAwIEEDBGBgNVHSAEPzA9MDsGDCsGAQQBsjEBAgEDAjArMCkGCCsGAQUF
+BwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8ubmV0L0NQUzBDBgNVHR8EPDA6MDig
+NqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDb2RlU2lnbmlu
+Z0NBLmNybDB0BggrBgEFBQcBAQRoMGYwPgYIKwYBBQUHMAKGMmh0dHA6Ly9jcnQu
+Y29tb2RvY2EuY29tL0NPTU9ET1JTQUNvZGVTaWduaW5nQ0EuY3J0MCQGCCsGAQUF
+BzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEB
+AGnBSi9K/9rgTAyKFKrfGWSfNOwAghmsnsvpZSQ7QyoGWBFKSgCs/70kErl18oHA
+g7Y8loQB1yukZmJaCa3OvGud7smn45TCh0TMf4EpP20Wxf4rMQTxwAatasHL3+vi
+I+Nl5bsRZ09kWjvayqLII5upjS/yq0JfpmyGl5k2C/fIpztq0iOLvqWlXcL4+51r
+cMUAfX6E6EaZQm//ikp+w2+7MEXTKguOuV3gwsrTy0DsvkZl4YDgx/FA4ImzXopv
+d+3KJPLvO+OSBqUD3JPwXHnuJqGAbLBFyyCa/feGUjLlR8cxcNWLWdp4qxtoIUPG
+3wTsC9YgrglS0F7FKMXlNRY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF4DCCA8igAwIBAgIQLnyHzA6TSlL+lP0ct800rzANBgkqhkiG9w0BAQwFADCB
+hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
+BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTMwNTA5
+MDAwMDAwWhcNMjgwNTA4MjM1OTU5WjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
+T01PRE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25p
+bmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmmJBjd5E0f4rR
+3elnMRHrzB79MR2zuWJXP5O8W+OfHiQyESdrvFGRp8+eniWzX4GoGA8dHiAwDvth
+e4YJs+P9omidHCydv3Lj5HWg5TUjjsmK7hoMZMfYQqF7tVIDSzqwjiNLS2PgIpQ3
+e9V5kAoUGFEs5v7BEvAcP2FhCoyi3PbDMKrNKBh1SMF5WgjNu4xVjPfUdpA6M0ZQ
+c5hc9IVKaw+A3V7Wvf2pL8Al9fl4141fEMJEVTyQPDFGy3CuB6kK46/BAW+QGiPi
+XzjbxghdR7ODQfAuADcUuRKqeZJSzYcPe9hiKaR+ML0btYxytEjy4+gh+V5MYnmL
+Agaff9ULAgMBAAGjggFRMIIBTTAfBgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs
+2TIy1DAdBgNVHQ4EFgQUKZFg/4pN+uv5pmq4z/nmS71JzhIwDgYDVR0PAQH/BAQD
+AgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYD
+VR0gBAowCDAGBgRVHSAAMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29t
+b2RvY2EuY29tL0NPTU9ET1JTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEG
+CCsGAQUFBwEBBGUwYzA7BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5j
+b20vQ09NT0RPUlNBQWRkVHJ1c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
+Y3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAAj8COcPu+Mo7id4M
+bU2x8U6ST6/COCwEzMVjEasJY6+rotcCP8xvGcM91hoIlP8l2KmIpysQGuCbsQci
+GlEcOtTh6Qm/5iR0rx57FjFuI+9UUS1SAuJ1CAVM8bdR4VEAxof2bO4QRHZXavHf
+WGshqknUfDdOvf+2dVRAGDZXZxHNTwLk/vPa/HUX2+y392UJI0kfQ1eD6n4gd2HI
+TfK7ZU2o94VFB696aSdlkClAi997OlE5jKgfcHmtbUIgos8MbAOMTM1zB5TnWo46
+BLqioXwfy2M6FafUFRunUkcyqfS/ZEfRqh9TTjIwc8Jvt3iCnVz/RrtrIh2IC/gb
+qjSm/Iz13X9ljIwxVzHQNuxHoc/Li6jvHBhYxQZ3ykubUa9MCEp6j+KjUuKOjswm
+5LLY5TjCqO3GgZw1a6lYYUoKl7RLQrZVnb6Z53BtWfhtKgx/GWBfDJqIbDCsUgmQ
+Fhv/K53b0CDKieoofjKOGd97SDMe12X4rsn4gxSTdn1k0I7OvjV9/3IxTZ+evR5s
+L6iPDAZQ+4wns3bJ9ObXwzTijIchhmH+v1V04SF3AwpobLvkyanmz1kl63zsRQ55
+ZmjoIs2475iFTZYRPAmK0H+8KCgT+2rKVI2SXM3CZZgGns5IW9S1N5NGQXwH3c/6
+Q++6Z2H/fUnguzB9XIDj5hY5S6c=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
+hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
+BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5
+MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
+EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR
+6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X
+pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC
+9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV
+/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf
+Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z
++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w
+qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah
+SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC
+u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf
+Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq
+crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
+FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
+/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl
+wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM
+4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV
+2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna
+FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ
+CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK
+boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke
+jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL
+S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb
+QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
+0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB
+NVOFBkpdn627G190
+-----END CERTIFICATE-----
diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py
index 6268123dd8..ea398a27ea 100755
--- a/contrib/zmq/zmq_sub.py
+++ b/contrib/zmq/zmq_sub.py
@@ -1,41 +1,84 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+
+"""
+ ZMQ example using python3's asyncio
+
+ Bitcoin should be started with the command line arguments:
+ bitcoind -testnet -daemon \
+ -zmqpubhashblock=tcp://127.0.0.1:28332 \
+ -zmqpubrawtx=tcp://127.0.0.1:28332 \
+ -zmqpubhashtx=tcp://127.0.0.1:28332 \
+ -zmqpubhashblock=tcp://127.0.0.1:28332
+
+ We use the asyncio library here. `self.handle()` installs itself as a
+ future at the end of the function. Since it never returns with the event
+ loop having an empty stack of futures, this creates an infinite loop. An
+ alternative is to wrap the contents of `handle` inside `while True`.
+
+ A blocking example using python 2.7 can be obtained from the git history:
+ https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py
+"""
-import array
import binascii
+import asyncio
import zmq
+import zmq.asyncio
+import signal
import struct
+import sys
+
+if not (sys.version_info.major >= 3 and sys.version_info.minor >= 5):
+ print("This example only works with Python 3.5 and greater")
+ exit(1)
port = 28332
-zmqContext = zmq.Context()
-zmqSubSocket = zmqContext.socket(zmq.SUB)
-zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashblock")
-zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashtx")
-zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "rawblock")
-zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "rawtx")
-zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
-
-try:
- while True:
- msg = zmqSubSocket.recv_multipart()
- topic = str(msg[0])
+class ZMQHandler():
+ def __init__(self):
+ self.loop = zmq.asyncio.install()
+ self.zmqContext = zmq.asyncio.Context()
+
+ self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
+ self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock")
+ self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx")
+ self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock")
+ self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx")
+ self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
+
+ async def handle(self) :
+ msg = await self.zmqSubSocket.recv_multipart()
+ topic = msg[0]
body = msg[1]
- sequence = "Unknown";
+ sequence = "Unknown"
if len(msg[-1]) == 4:
msgSequence = struct.unpack('<I', msg[-1])[-1]
sequence = str(msgSequence)
- if topic == "hashblock":
- print '- HASH BLOCK ('+sequence+') -'
- print binascii.hexlify(body)
- elif topic == "hashtx":
- print '- HASH TX ('+sequence+') -'
- print binascii.hexlify(body)
- elif topic == "rawblock":
- print '- RAW BLOCK HEADER ('+sequence+') -'
- print binascii.hexlify(body[:80])
- elif topic == "rawtx":
- print '- RAW TX ('+sequence+') -'
- print binascii.hexlify(body)
-
-except KeyboardInterrupt:
- zmqContext.destroy()
+ if topic == b"hashblock":
+ print('- HASH BLOCK ('+sequence+') -')
+ print(binascii.hexlify(body))
+ elif topic == b"hashtx":
+ print('- HASH TX ('+sequence+') -')
+ print(binascii.hexlify(body))
+ elif topic == b"rawblock":
+ print('- RAW BLOCK HEADER ('+sequence+') -')
+ print(binascii.hexlify(body[:80]))
+ elif topic == b"rawtx":
+ print('- RAW TX ('+sequence+') -')
+ print(binascii.hexlify(body))
+ # schedule ourselves to receive the next message
+ asyncio.ensure_future(self.handle())
+
+ def start(self):
+ self.loop.add_signal_handler(signal.SIGINT, self.stop)
+ self.loop.create_task(self.handle())
+ self.loop.run_forever()
+
+ def stop(self):
+ self.loop.stop()
+ self.zmqContext.destroy()
+
+daemon = ZMQHandler()
+daemon.start()
diff --git a/contrib/zmq/zmq_sub3.4.py b/contrib/zmq/zmq_sub3.4.py
new file mode 100755
index 0000000000..1cb7eec0c0
--- /dev/null
+++ b/contrib/zmq/zmq_sub3.4.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+
+"""
+ ZMQ example using python3's asyncio
+
+ Bitcoin should be started with the command line arguments:
+ bitcoind -testnet -daemon \
+ -zmqpubhashblock=tcp://127.0.0.1:28332 \
+ -zmqpubrawtx=tcp://127.0.0.1:28332 \
+ -zmqpubhashtx=tcp://127.0.0.1:28332 \
+ -zmqpubhashblock=tcp://127.0.0.1:28332
+
+ We use the asyncio library here. `self.handle()` installs itself as a
+ future at the end of the function. Since it never returns with the event
+ loop having an empty stack of futures, this creates an infinite loop. An
+ alternative is to wrap the contents of `handle` inside `while True`.
+
+ The `@asyncio.coroutine` decorator and the `yield from` syntax found here
+ was introduced in python 3.4 and has been deprecated in favor of the `async`
+ and `await` keywords respectively.
+
+ A blocking example using python 2.7 can be obtained from the git history:
+ https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py
+"""
+
+import binascii
+import asyncio
+import zmq
+import zmq.asyncio
+import signal
+import struct
+import sys
+
+if not (sys.version_info.major >= 3 and sys.version_info.minor >= 4):
+ print("This example only works with Python 3.4 and greater")
+ exit(1)
+
+port = 28332
+
+class ZMQHandler():
+ def __init__(self):
+ self.loop = zmq.asyncio.install()
+ self.zmqContext = zmq.asyncio.Context()
+
+ self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
+ self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock")
+ self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx")
+ self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock")
+ self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx")
+ self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
+
+ @asyncio.coroutine
+ def handle(self) :
+ msg = yield from self.zmqSubSocket.recv_multipart()
+ topic = msg[0]
+ body = msg[1]
+ sequence = "Unknown"
+ if len(msg[-1]) == 4:
+ msgSequence = struct.unpack('<I', msg[-1])[-1]
+ sequence = str(msgSequence)
+ if topic == b"hashblock":
+ print('- HASH BLOCK ('+sequence+') -')
+ print(binascii.hexlify(body))
+ elif topic == b"hashtx":
+ print('- HASH TX ('+sequence+') -')
+ print(binascii.hexlify(body))
+ elif topic == b"rawblock":
+ print('- RAW BLOCK HEADER ('+sequence+') -')
+ print(binascii.hexlify(body[:80]))
+ elif topic == b"rawtx":
+ print('- RAW TX ('+sequence+') -')
+ print(binascii.hexlify(body))
+ # schedule ourselves to receive the next message
+ asyncio.ensure_future(self.handle())
+
+ def start(self):
+ self.loop.add_signal_handler(signal.SIGINT, self.stop)
+ self.loop.create_task(self.handle())
+ self.loop.run_forever()
+
+ def stop(self):
+ self.loop.stop()
+ self.zmqContext.destroy()
+
+daemon = ZMQHandler()
+daemon.start()
diff --git a/depends/config.guess b/depends/config.guess
index c4bd827a7b..69ed3e573b 100755
--- a/depends/config.guess
+++ b/depends/config.guess
@@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2016 Free Software Foundation, Inc.
+# Copyright 1992-2017 Free Software Foundation, Inc.
-timestamp='2016-05-15'
+timestamp='2017-03-05'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2016 Free Software Foundation, Inc.
+Copyright 1992-2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -837,10 +837,11 @@ EOF
UNAME_PROCESSOR=`/usr/bin/uname -p`
case ${UNAME_PROCESSOR} in
amd64)
- echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- *)
- echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ UNAME_PROCESSOR=x86_64 ;;
+ i386)
+ UNAME_PROCESSOR=i586 ;;
esac
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
@@ -1000,6 +1001,9 @@ EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
;;
+ mips64el:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
openrisc*:Linux:*:*)
echo or1k-unknown-linux-${LIBC}
exit ;;
@@ -1032,6 +1036,9 @@ EOF
ppcle:Linux:*:*)
echo powerpcle-unknown-linux-${LIBC}
exit ;;
+ riscv32:Linux:*:* | riscv64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
exit ;;
@@ -1337,6 +1344,9 @@ EOF
NSR-?:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
exit ;;
+ NSX-?:NONSTOP_KERNEL:*:*)
+ echo nsx-tandem-nsk${UNAME_RELEASE}
+ exit ;;
*:NonStop-UX:*:*)
echo mips-compaq-nonstopux
exit ;;
diff --git a/depends/config.site.in b/depends/config.site.in
index e731537bf7..3d7c9fd43c 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -19,9 +19,6 @@ fi
if test -z $with_protoc_bindir; then
with_protoc_bindir=$depends_prefix/native/bin
fi
-if test -z $with_comparison_tool; then
- with_comparison_tool=$depends_prefix/native/share/BitcoindComparisonTool_jar/BitcoindComparisonTool.jar
-fi
if test -z $enable_wallet && test -n "@no_wallet@"; then
@@ -66,7 +63,6 @@ LDFLAGS="-L$depends_prefix/lib $LDFLAGS"
CC="@CC@"
CXX="@CXX@"
OBJC="${CC}"
-OBJCXX="${CXX}"
CCACHE=$depends_prefix/native/bin/ccache
PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH
diff --git a/depends/config.sub b/depends/config.sub
index 6d86a1e2f7..40ea5dfe11 100755
--- a/depends/config.sub
+++ b/depends/config.sub
@@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2016 Free Software Foundation, Inc.
+# Copyright 1992-2017 Free Software Foundation, Inc.
-timestamp='2016-05-10'
+timestamp='2017-04-02'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -67,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2016 Free Software Foundation, Inc.
+Copyright 1992-2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -117,7 +117,7 @@ case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
- kopensolaris*-gnu* | \
+ kopensolaris*-gnu* | cloudabi*-eabi* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
@@ -263,7 +263,7 @@ case $basic_machine in
| fido | fr30 | frv | ft32 \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
- | i370 | i860 | i960 | ia64 \
+ | i370 | i860 | i960 | ia16 | ia64 \
| ip2k | iq2000 \
| k1om \
| le32 | le64 \
@@ -301,6 +301,7 @@ case $basic_machine in
| open8 | or1k | or1knd | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pru \
| pyramid \
| riscv32 | riscv64 \
| rl78 | rx \
@@ -314,6 +315,7 @@ case $basic_machine in
| ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| visium \
+ | wasm32 \
| we32k \
| x86 | xc16x | xstormy16 | xtensa \
| z8k | z80)
@@ -387,7 +389,7 @@ case $basic_machine in
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| hexagon-* \
- | i*86-* | i860-* | i960-* | ia64-* \
+ | i*86-* | i860-* | i960-* | ia16-* | ia64-* \
| ip2k-* | iq2000-* \
| k1om-* \
| le32-* | le64-* \
@@ -428,6 +430,7 @@ case $basic_machine in
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pru-* \
| pyramid-* \
| riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \
@@ -444,6 +447,7 @@ case $basic_machine in
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \
| visium-* \
+ | wasm32-* \
| we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \
@@ -643,6 +647,14 @@ case $basic_machine in
basic_machine=m68k-bull
os=-sysv3
;;
+ e500v[12])
+ basic_machine=powerpc-unknown
+ os=$os"spe"
+ ;;
+ e500v[12]-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=$os"spe"
+ ;;
ebmon29k)
basic_machine=a29k-amd
os=-ebmon
@@ -938,6 +950,9 @@ case $basic_machine in
nsr-tandem)
basic_machine=nsr-tandem
;;
+ nsx-tandem)
+ basic_machine=nsx-tandem
+ ;;
op50n-* | op60c-*)
basic_machine=hppa1.1-oki
os=-proelf
@@ -1022,7 +1037,7 @@ case $basic_machine in
ppc-* | ppcbe-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
- ppcle | powerpclittle | ppc-le | powerpc-little)
+ ppcle | powerpclittle)
basic_machine=powerpcle-unknown
;;
ppcle-* | powerpclittle-*)
@@ -1032,7 +1047,7 @@ case $basic_machine in
;;
ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
- ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ ppc64le | powerpc64little)
basic_machine=powerpc64le-unknown
;;
ppc64le-* | powerpc64little-*)
@@ -1233,6 +1248,9 @@ case $basic_machine in
basic_machine=a29k-wrs
os=-vxworks
;;
+ wasm32)
+ basic_machine=wasm32-unknown
+ ;;
w65*)
basic_machine=w65-wdc
os=-none
@@ -1387,9 +1405,9 @@ case $os in
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -chorusos* | -chorusrdb* | -cegcc* \
+ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
@@ -1399,7 +1417,7 @@ case $os in
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
- | -onefs* | -tirtos* | -phoenix*)
+ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1628,6 +1646,9 @@ case $basic_machine in
sparc-* | *-sun)
os=-sunos4.1.1
;;
+ pru-*)
+ os=-elf
+ ;;
*-be)
os=-beos
;;
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk
index 985649619f..4e58bec74e 100644
--- a/depends/hosts/darwin.mk
+++ b/depends/hosts/darwin.mk
@@ -1,4 +1,4 @@
-OSX_MIN_VERSION=10.7
+OSX_MIN_VERSION=10.8
OSX_SDK_VERSION=10.11
OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk
LD64_VERSION=253.9
diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk
index ef1307c241..bf773ccd14 100644
--- a/depends/packages/boost.mk
+++ b/depends/packages/boost.mk
@@ -1,8 +1,8 @@
package=boost
-$(package)_version=1_59_0
-$(package)_download_path=http://sourceforge.net/projects/boost/files/boost/1.59.0
+$(package)_version=1_64_0
+$(package)_download_path=https://dl.bintray.com/boostorg/release/1.64.0/source/
$(package)_file_name=$(package)_$($(package)_version).tar.bz2
-$(package)_sha256_hash=727a932322d94287b62abb1bd2d41723eec4356a7728909e38adb65ca25241ca
+$(package)_sha256_hash=7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332
define $(package)_set_vars
$(package)_config_opts_release=variant=release
diff --git a/depends/packages/dbus.mk b/depends/packages/dbus.mk
index 8ac9ab742b..bbe0375409 100644
--- a/depends/packages/dbus.mk
+++ b/depends/packages/dbus.mk
@@ -1,8 +1,8 @@
package=dbus
-$(package)_version=1.8.6
-$(package)_download_path=http://dbus.freedesktop.org/releases/dbus
+$(package)_version=1.10.18
+$(package)_download_path=https://dbus.freedesktop.org/releases/dbus
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=eded83ca007b719f32761e60fd8b9ffd0f5796a4caf455b01b5a5ef740ebd23f
+$(package)_sha256_hash=6049ddd5f3f3e2618f615f1faeda0a115104423a7996b7aa73e2f36e38cc514a
$(package)_dependencies=expat
define $(package)_set_vars
diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk
index bd29275638..81a660e83a 100644
--- a/depends/packages/expat.mk
+++ b/depends/packages/expat.mk
@@ -1,8 +1,8 @@
package=expat
-$(package)_version=2.1.1
+$(package)_version=2.2.0
$(package)_download_path=https://downloads.sourceforge.net/project/expat/expat/$($(package)_version)
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=aff584e5a2f759dcfc6d48671e9529f6afe1e30b0cd6a4cec200cbe3f793de67
+$(package)_sha256_hash=d9e50ff2d19b3538bd2127902a89987474e1a4db8e43a66a4d1a712ab9a504ff
define $(package)_set_vars
$(package)_config_opts=--disable-static
diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk
index 2cf553ed96..fb97e0b9ec 100644
--- a/depends/packages/fontconfig.mk
+++ b/depends/packages/fontconfig.mk
@@ -1,8 +1,8 @@
package=fontconfig
-$(package)_version=2.11.1
+$(package)_version=2.12.1
$(package)_download_path=http://www.freedesktop.org/software/fontconfig/release/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=dc62447533bca844463a3c3fd4083b57c90f18a70506e7a9f4936b5a1e516a99
+$(package)_sha256_hash=b449a3e10c47e1d1c7a6ec6e2016cca73d3bd68fbbd4f0ae5cc6b573f7d6c7f3
$(package)_dependencies=freetype expat
define $(package)_set_vars
diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk
index 7cea28ff0b..76b025c463 100644
--- a/depends/packages/freetype.mk
+++ b/depends/packages/freetype.mk
@@ -1,8 +1,8 @@
package=freetype
-$(package)_version=2.6.3
+$(package)_version=2.7.1
$(package)_download_path=http://download.savannah.gnu.org/releases/$(package)
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=371e707aa522acf5b15ce93f11183c725b8ed1ee8546d7b3af549863045863a2
+$(package)_sha256_hash=3a3bb2c4e15ffb433f2032f50a5b5a92558206822e22bfe8cbe339af4aa82f88
define $(package)_set_vars
$(package)_config_opts=--without-zlib --without-png --disable-static
diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk
index 2e9be1e98c..00231d75d5 100644
--- a/depends/packages/libevent.mk
+++ b/depends/packages/libevent.mk
@@ -1,12 +1,11 @@
package=libevent
-$(package)_version=2.0.22
-$(package)_download_path=https://github.com/libevent/libevent/releases/download/release-2.0.22-stable
-$(package)_file_name=$(package)-$($(package)_version)-stable.tar.gz
-$(package)_sha256_hash=71c2c49f0adadacfdbe6332a372c38cf9c8b7895bb73dabeaa53cdcc1d4e1fa3
-$(package)_patches=reuseaddr.patch
+$(package)_version=2.1.8-stable
+$(package)_download_path=https://github.com/libevent/libevent/archive/
+$(package)_file_name=release-$($(package)_version).tar.gz
+$(package)_sha256_hash=316ddb401745ac5d222d7c529ef1eada12f58f6376a66c1118eee803cb70f83d
define $(package)_preprocess_cmds
- patch -p1 < $($(package)_patch_dir)/reuseaddr.patch
+ ./autogen.sh
endef
define $(package)_set_vars
diff --git a/depends/packages/native_biplist.mk b/depends/packages/native_biplist.mk
index eb8672d556..3c6e8900f6 100644
--- a/depends/packages/native_biplist.mk
+++ b/depends/packages/native_biplist.mk
@@ -4,6 +4,11 @@ $(package)_download_path=https://pypi.python.org/packages/source/b/biplist
$(package)_file_name=biplist-$($(package)_version).tar.gz
$(package)_sha256_hash=b57cadfd26e4754efdf89e9e37de87885f9b5c847b2615688ca04adfaf6ca604
$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages
+$(package)_patches=sorted_list.patch
+
+define $(package)_preprocess_cmds
+ patch -p1 < $($(package)_patch_dir)/sorted_list.patch
+endef
define $(package)_build_cmds
python setup.py build
diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk
index 9216e17598..966804ce8b 100644
--- a/depends/packages/native_ccache.mk
+++ b/depends/packages/native_ccache.mk
@@ -1,8 +1,8 @@
package=native_ccache
-$(package)_version=3.2.5
-$(package)_download_path=http://samba.org/ftp/ccache
+$(package)_version=3.3.4
+$(package)_download_path=https://samba.org/ftp/ccache
$(package)_file_name=ccache-$($(package)_version).tar.bz2
-$(package)_sha256_hash=7a553809e90faf9de3a23ee9c5b5f786cfd4836bf502744bedb824a24bee1097
+$(package)_sha256_hash=fa9d7f38367431bc86b19ad107d709ca7ecf1574fdacca01698bdf0a47cd8567
define $(package)_set_vars
$(package)_config_opts=
diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk
index 797480c25e..44d238cc4c 100644
--- a/depends/packages/native_cctools.mk
+++ b/depends/packages/native_cctools.mk
@@ -38,7 +38,8 @@ $(package)_cxx=$($(package)_extract_dir)/toolchain/bin/clang++
endef
define $(package)_preprocess_cmds
- cd $($(package)_build_subdir); ./autogen.sh
+ cd $($(package)_build_subdir); ./autogen.sh && \
+ sed -i.old "/define HAVE_PTHREADS/d" ld64/src/ld/InputFiles.h
endef
define $(package)_config_cmds
diff --git a/depends/packages/native_comparisontool.mk b/depends/packages/native_comparisontool.mk
deleted file mode 100644
index e0ae0cec70..0000000000
--- a/depends/packages/native_comparisontool.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-package=native_comparisontool
-$(package)_version=8c6666f
-$(package)_download_path=https://github.com/theuni/bitcoind-comparisontool/raw/master
-$(package)_file_name=pull-tests-$($(package)_version).jar
-$(package)_sha256_hash=a865332b3827abcde684ab79f5f43c083b0b6a4c97ff5508c79f29fee24f11cd
-$(package)_install_dirname=BitcoindComparisonTool_jar
-$(package)_install_filename=BitcoindComparisonTool.jar
-
-define $(package)_extract_cmds
-endef
-
-define $(package)_configure_cmds
-endef
-
-define $(package)_build_cmds
-endef
-
-define $(package)_stage_cmds
- mkdir -p $($(package)_staging_prefix_dir)/share/$($(package)_install_dirname) && \
- cp $($(package)_source) $($(package)_staging_prefix_dir)/share/$($(package)_install_dirname)/$($(package)_install_filename)
-endef
diff --git a/depends/packages/native_ds_store.mk b/depends/packages/native_ds_store.mk
index 8e902af1b6..49f5829ac1 100644
--- a/depends/packages/native_ds_store.mk
+++ b/depends/packages/native_ds_store.mk
@@ -1,9 +1,9 @@
package=native_ds_store
-$(package)_version=c80c23706eae
+$(package)_version=1.1.0
$(package)_download_path=https://bitbucket.org/al45tair/ds_store/get
-$(package)_download_file=$($(package)_version).tar.bz2
+$(package)_download_file=v$($(package)_version).tar.bz2
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=ce1aa412211610c63d567bbe3e06213006a2d5ba5d76d89399c151b5472cb0da
+$(package)_sha256_hash=921596764d71d1bbd3297a90ef6d286f718794d667e4f81d91d14053525d64c1
$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages
$(package)_dependencies=native_biplist
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index ac43ef4a2e..088723ebd0 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -1,10 +1,8 @@
-packages:=boost openssl libevent
-darwin_packages:=zeromq
-linux_packages:=zeromq
-native_packages := native_ccache native_comparisontool
+packages:=boost openssl libevent zeromq
+native_packages := native_ccache
qt_native_packages = native_protobuf
-qt_packages = qrencode protobuf
+qt_packages = qrencode protobuf zlib
qt_x86_64_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans
qt_i686_linux_packages:=$(qt_x86_64_linux_packages)
@@ -12,7 +10,6 @@ qt_i686_linux_packages:=$(qt_x86_64_linux_packages)
qt_darwin_packages=qt
qt_mingw32_packages=qt
-
wallet_packages=bdb
upnp_packages=miniupnpc
diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk
index 7b21247133..44fdf1c295 100644
--- a/depends/packages/qrencode.mk
+++ b/depends/packages/qrencode.mk
@@ -1,7 +1,7 @@
package=qrencode
$(package)_version=3.4.4
$(package)_download_path=https://fukuchi.org/works/qrencode/
-$(package)_file_name=qrencode-$(qrencode_version).tar.bz2
+$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19cde1fa5
define $(package)_set_vars
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index d41d0b9ea5..bbfdb766ed 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -1,30 +1,30 @@
PACKAGE=qt
-$(package)_version=5.6.1
-$(package)_download_path=http://download.qt.io/official_releases/qt/5.6/$($(package)_version)/submodules
+$(package)_version=5.7.1
+$(package)_download_path=http://download.qt.io/official_releases/qt/5.7/$($(package)_version)/submodules
$(package)_suffix=opensource-src-$($(package)_version).tar.gz
$(package)_file_name=qtbase-$($(package)_suffix)
-$(package)_sha256_hash=0ac67cf8d66d52b995f96c31c4b48117a1afb3db99eaa93e20ccd8f7f55f7fde
-$(package)_dependencies=openssl
+$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410
+$(package)_dependencies=openssl zlib
$(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext
$(package)_build_subdir=qtbase
$(package)_qt_libs=corelib network widgets gui plugins testlib
$(package)_patches=mac-qmake.conf mingw-uuidof.patch pidlist_absolute.patch fix-xcb-include-order.patch fix_qt_pkgconfig.patch
$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix)
-$(package)_qttranslations_sha256_hash=dcc1534d247babca1840cb6d0a000671801a341ea352d0535474f86adadaf028
+$(package)_qttranslations_sha256_hash=3a15aebd523c6d89fb97b2d3df866c94149653a26d27a00aac9b6d3020bc5a1d
$(package)_qttools_file_name=qttools-$($(package)_suffix)
-$(package)_qttools_sha256_hash=e0f845de28c31230dfa428f0190ccb3b91d1fc02481b1f064698ae4ef8376aa1
+$(package)_qttools_sha256_hash=22d67de915cb8cd93e16fdd38fa006224ad9170bd217c2be1e53045a8dd02f0f
$(package)_extra_sources = $($(package)_qttranslations_file_name)
$(package)_extra_sources += $($(package)_qttools_file_name)
define $(package)_set_vars
$(package)_config_opts_release = -release
-$(package)_config_opts_debug = -debug
+$(package)_config_opts_debug = -debug
$(package)_config_opts += -bindir $(build_prefix)/bin
-$(package)_config_opts += -c++11
+$(package)_config_opts += -c++std c++11
$(package)_config_opts += -confirm-license
$(package)_config_opts += -dbus-runtime
$(package)_config_opts += -hostprefix $(build_prefix)
@@ -46,7 +46,6 @@ $(package)_config_opts += -no-linuxfb
$(package)_config_opts += -no-libudev
$(package)_config_opts += -no-mitshm
$(package)_config_opts += -no-mtdev
-$(package)_config_opts += -no-nis
$(package)_config_opts += -no-pulseaudio
$(package)_config_opts += -no-openvg
$(package)_config_opts += -no-reduce-relocations
@@ -74,11 +73,13 @@ $(package)_config_opts += -prefix $(host_prefix)
$(package)_config_opts += -qt-libpng
$(package)_config_opts += -qt-libjpeg
$(package)_config_opts += -qt-pcre
-$(package)_config_opts += -qt-zlib
+$(package)_config_opts += -system-zlib
$(package)_config_opts += -reduce-exports
$(package)_config_opts += -static
$(package)_config_opts += -silent
$(package)_config_opts += -v
+$(package)_config_opts += -no-feature-printer
+$(package)_config_opts += -no-feature-printdialog
ifneq ($(build_os),darwin)
$(package)_config_opts_darwin = -xplatform macx-clang-linux
@@ -125,6 +126,7 @@ endef
define $(package)_preprocess_cmds
sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \
+ sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \
sed -i.old "s/src_plugins.depends = src_sql src_xml src_network/src_plugins.depends = src_xml src_network/" qtbase/src/src.pro && \
sed -i.old "s|X11/extensions/XIproto.h|X11/X.h|" qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp && \
sed -i.old 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' qtbase/configure && \
@@ -138,12 +140,13 @@ define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/pidlist_absolute.patch && \
patch -p1 < $($(package)_patch_dir)/fix-xcb-include-order.patch && \
patch -p1 < $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \
- echo "QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
- echo "QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
- echo "QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
- sed -i.old "s|QMAKE_CFLAGS = |QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \
- sed -i.old "s|QMAKE_LFLAGS = |QMAKE_LFLAGS = $($(package)_ldflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \
- sed -i.old "s|QMAKE_CXXFLAGS = |QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf
+ echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
+ echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
+ echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
+ sed -i.old "s|QMAKE_CFLAGS = |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \
+ sed -i.old "s|QMAKE_LFLAGS = |!host_build: QMAKE_LFLAGS = $($(package)_ldflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \
+ sed -i.old "s|QMAKE_CXXFLAGS = |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf
+
endef
define $(package)_config_cmds
@@ -151,6 +154,8 @@ define $(package)_config_cmds
export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \
export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \
./configure $($(package)_config_opts) && \
+ echo "host_build: QT_CONFIG ~= s/system-zlib/zlib" >> mkspecs/qconfig.pri && \
+ echo "CONFIG += force_bootstrap" >> mkspecs/qconfig.pri && \
$(MAKE) sub-src-clean && \
cd ../qttranslations && ../qtbase/bin/qmake qttranslations.pro -o Makefile && \
cd translations && ../../qtbase/bin/qmake translations.pro -o Makefile && cd ../.. &&\
diff --git a/depends/packages/qt46.mk b/depends/packages/qt46.mk
deleted file mode 100644
index 8fb30a5c44..0000000000
--- a/depends/packages/qt46.mk
+++ /dev/null
@@ -1,66 +0,0 @@
-PACKAGE=qt46
-$(package)_version=4.6.4
-$(package)_download_path=http://download.qt-project.org/archive/qt/4.6/
-$(package)_file_name=qt-everywhere-opensource-src-$($(package)_version).tar.gz
-$(package)_sha256_hash=9ad4d46c721b53a429ed5a2eecfd3c239a9ab566562f183f99d3125f1a234250
-$(package)_dependencies=openssl freetype dbus libX11 xproto libXext libICE libSM
-$(package)_patches=stlfix.patch
-
-define $(package)_set_vars
-$(package)_config_opts = -prefix $(host_prefix) -headerdir $(host_prefix)/include/qt4 -bindir $(build_prefix)/bin
-$(package)_config_opts += -release -no-separate-debug-info -opensource -confirm-license
-$(package)_config_opts += -stl -qt-zlib
-
-$(package)_config_opts += -nomake examples -nomake tests -nomake tools -nomake translations -nomake demos -nomake docs
-$(package)_config_opts += -no-audio-backend -no-glib -no-nis -no-cups -no-iconv -no-gif -no-pch
-$(package)_config_opts += -no-xkb -no-xrender -no-xrandr -no-xfixes -no-xcursor -no-xinerama -no-xsync -no-xinput -no-mitshm -no-xshape
-$(package)_config_opts += -no-libtiff -no-fontconfig -openssl-linked
-$(package)_config_opts += -no-sql-db2 -no-sql-ibase -no-sql-oci -no-sql-tds -no-sql-mysql
-$(package)_config_opts += -no-sql-odbc -no-sql-psql -no-sql-sqlite -no-sql-sqlite2
-$(package)_config_opts += -no-xmlpatterns -no-multimedia -no-phonon -no-scripttools -no-declarative
-$(package)_config_opts += -no-phonon-backend -no-webkit -no-javascript-jit -no-script
-$(package)_config_opts += -no-svg -no-libjpeg -no-libtiff -no-libpng -no-libmng -no-qt3support -no-opengl
-
-$(package)_config_opts_x86_64_linux += -platform linux-g++-64
-$(package)_config_opts_i686_linux = -platform linux-g++-32
-$(package)_build_env = QT_RCC_TEST=1
-endef
-
-define $(package)_preprocess_cmds
- sed -i.old "s|/include /usr/include||" config.tests/unix/freetype/freetype.pri && \
- sed -i.old "s|src_plugins.depends = src_gui src_sql src_svg|src_plugins.depends = src_gui src_sql|" src/src.pro && \
- sed -i.old "s|\.lower(|\.toLower(|g" src/network/ssl/qsslsocket_openssl.cpp && \
- sed -i.old "s|Key_BackSpace|Key_Backspace|" src/gui/itemviews/qabstractitemview.cpp && \
- sed -i.old "s|/usr/X11R6/lib64|$(host_prefix)/lib|" mkspecs/*/*.conf && \
- sed -i.old "s|/usr/X11R6/lib|$(host_prefix)/lib|" mkspecs/*/*.conf && \
- sed -i.old "s|/usr/X11R6/include|$(host_prefix)/include|" mkspecs/*/*.conf && \
- sed -i.old "s|QMAKE_LFLAGS_SHLIB\t+= -shared|QMAKE_LFLAGS_SHLIB\t+= -shared -Wl,--exclude-libs,ALL|" mkspecs/common/g++.conf && \
- sed -i.old "/SSLv2_client_method/d" src/network/ssl/qsslsocket_openssl.cpp src/network/ssl/qsslsocket_openssl_symbols.cpp && \
- sed -i.old "/SSLv2_server_method/d" src/network/ssl/qsslsocket_openssl.cpp src/network/ssl/qsslsocket_openssl_symbols.cpp && \
- patch -p1 < $($(package)_patch_dir)/stlfix.patch
-endef
-
-define $(package)_config_cmds
- export PKG_CONFIG_SYSROOT_DIR=/ && \
- export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \
- export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \
- export CPATH=$(host_prefix)/include && \
- OPENSSL_LIBS='-L$(host_prefix)/lib -lssl -lcrypto' ./configure $($(package)_config_opts) && \
- cd tools/linguist/lrelease; ../../../bin/qmake -o Makefile lrelease.pro
-endef
-
-define $(package)_build_cmds
- export CPATH=$(host_prefix)/include && \
- $(MAKE) -C src && \
- $(MAKE) -C tools/linguist/lrelease
-endef
-
-define $(package)_stage_cmds
- $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) install && \
- $(MAKE) -C tools/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install
-endef
-
-define $(package)_postprocess_cmds
- rm -rf mkspecs/ lib/cmake/ lib/*.prl lib/*.la && \
- find native/bin -type f -exec mv {} {}-qt4 \;
-endef
diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk
index f8901f72c2..01146c26f6 100644
--- a/depends/packages/zeromq.mk
+++ b/depends/packages/zeromq.mk
@@ -1,15 +1,22 @@
package=zeromq
-$(package)_version=4.1.4
-$(package)_download_path=http://download.zeromq.org
+$(package)_version=4.1.5
+$(package)_download_path=https://github.com/zeromq/zeromq4-1/releases/download/v$($(package)_version)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=e99f44fde25c2e4cb84ce440f87ca7d3fe3271c2b8cfbc67d55e4de25e6fe378
+$(package)_sha256_hash=04aac57f081ffa3a2ee5ed04887be9e205df3a7ddade0027460b8042432bdbcf
+$(package)_patches=9114d3957725acd34aa8b8d011585812f3369411.patch 9e6745c12e0b100cd38acecc16ce7db02905e27c.patch
define $(package)_set_vars
- $(package)_config_opts=--without-documentation --disable-shared --without-libsodium
+ $(package)_config_opts=--without-documentation --disable-shared --without-libsodium --disable-curve
$(package)_config_opts_linux=--with-pic
$(package)_cxxflags=-std=c++11
endef
+define $(package)_preprocess_cmds
+ patch -p1 < $($(package)_patch_dir)/9114d3957725acd34aa8b8d011585812f3369411.patch && \
+ patch -p1 < $($(package)_patch_dir)/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch && \
+ ./autogen.sh
+endef
+
define $(package)_config_cmds
$($(package)_autoconf)
endef
diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk
new file mode 100644
index 0000000000..589490800f
--- /dev/null
+++ b/depends/packages/zlib.mk
@@ -0,0 +1,27 @@
+package=zlib
+$(package)_version=1.2.11
+$(package)_download_path=http://www.zlib.net
+$(package)_file_name=$(package)-$($(package)_version).tar.gz
+$(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
+
+define $(package)_set_vars
+$(package)_build_opts= CC="$($(package)_cc)"
+$(package)_build_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC"
+$(package)_build_opts+=RANLIB="$($(package)_ranlib)"
+$(package)_build_opts+=AR="$($(package)_ar)"
+$(package)_build_opts_darwin+=AR="$($(package)_libtool)"
+$(package)_build_opts_darwin+=ARFLAGS="-o"
+endef
+
+define $(package)_config_cmds
+ ./configure --static --prefix=$(host_prefix)
+endef
+
+define $(package)_build_cmds
+ $(MAKE) $($(package)_build_opts) libz.a
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) DESTDIR=$($(package)_staging_dir) install $($(package)_build_opts)
+endef
+
diff --git a/depends/patches/libevent/reuseaddr.patch b/depends/patches/libevent/reuseaddr.patch
deleted file mode 100644
index 58695c11f5..0000000000
--- a/depends/patches/libevent/reuseaddr.patch
+++ /dev/null
@@ -1,21 +0,0 @@
---- old/evutil.c 2015-08-28 19:26:23.488765923 -0400
-+++ new/evutil.c 2015-08-28 19:27:41.392767019 -0400
-@@ -321,15 +321,16 @@
- int
- evutil_make_listen_socket_reuseable(evutil_socket_t sock)
- {
--#ifndef WIN32
- int one = 1;
-+#ifndef WIN32
- /* REUSEADDR on Unix means, "don't hang on to this address after the
- * listener is closed." On Windows, though, it means "don't keep other
- * processes from binding to this address while we're using it. */
- return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
- (ev_socklen_t)sizeof(one));
- #else
-- return 0;
-+ return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*) &one,
-+ (ev_socklen_t)sizeof(one));
- #endif
- }
-
diff --git a/depends/patches/native_biplist/sorted_list.patch b/depends/patches/native_biplist/sorted_list.patch
new file mode 100644
index 0000000000..89abdb1b71
--- /dev/null
+++ b/depends/patches/native_biplist/sorted_list.patch
@@ -0,0 +1,29 @@
+--- a/biplist/__init__.py 2014-10-26 19:03:11.000000000 +0000
++++ b/biplist/__init__.py 2016-07-19 19:30:17.663521999 +0000
+@@ -541,7 +541,7 @@
+ return HashableWrapper(n)
+ elif isinstance(root, dict):
+ n = {}
+- for key, value in iteritems(root):
++ for key, value in sorted(iteritems(root)):
+ n[self.wrapRoot(key)] = self.wrapRoot(value)
+ return HashableWrapper(n)
+ elif isinstance(root, list):
+@@ -616,7 +616,7 @@
+ elif isinstance(obj, dict):
+ size = proc_size(len(obj))
+ self.incrementByteCount('dictBytes', incr=1+size)
+- for key, value in iteritems(obj):
++ for key, value in sorted(iteritems(obj)):
+ check_key(key)
+ self.computeOffsets(key, asReference=True)
+ self.computeOffsets(value, asReference=True)
+@@ -714,7 +714,7 @@
+ keys = []
+ values = []
+ objectsToWrite = []
+- for key, value in iteritems(obj):
++ for key, value in sorted(iteritems(obj)):
+ keys.append(key)
+ values.append(value)
+ for key in keys:
diff --git a/depends/patches/qt/fix-xcb-include-order.patch b/depends/patches/qt/fix-xcb-include-order.patch
index c7dbebedce..ec2bc17d9b 100644
--- a/depends/patches/qt/fix-xcb-include-order.patch
+++ b/depends/patches/qt/fix-xcb-include-order.patch
@@ -1,6 +1,6 @@
---- old/qtbase/src/plugins/platforms/xcb/xcb_qpa_lib.pro 2015-03-17 02:06:42.705930685 +0000
-+++ new/qtbase/src/plugins/platforms/xcb/xcb_qpa_lib.pro 2015-03-17 02:08:41.281926351 +0000
-@@ -74,8 +74,6 @@
+--- old/qtbase/src/plugins/platforms/xcb/xcb_qpa_lib.pro 2015-03-17
++++ new/qtbase/src/plugins/platforms/xcb/xcb_qpa_lib.pro 2015-03-17
+@@ -76,8 +76,6 @@
DEFINES += $$QMAKE_DEFINES_XCB
LIBS += $$QMAKE_LIBS_XCB
@@ -9,18 +9,18 @@
CONFIG += qpa/genericunixfontdatabase
-@@ -87,7 +85,8 @@
+@@ -89,7 +87,8 @@
contains(QT_CONFIG, xcb-qt) {
DEFINES += XCB_USE_RENDER
XCB_DIR = ../../../3rdparty/xcb
- INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/sysinclude
+ QMAKE_CFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/sysinclude $$QMAKE_CFLAGS_XCB
+ QMAKE_CXXFLAGS += -I$$XCB_DIR/include -I$$XCB_DIR/sysinclude $$QMAKE_CFLAGS_XCB
- LIBS += -lxcb -L$$OUT_PWD/xcb-static -lxcb-static
+ LIBS += -lxcb -L$$MODULE_BASE_OUTDIR/lib -lxcb-static$$qtPlatformTargetSuffix()
} else {
LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape -lxcb-keysyms -lxcb-xinerama
---- old/qtbase/src/plugins/platforms/xcb/xcb-static/xcb-static.pro 2015-03-17 02:07:04.641929383 +0000
-+++ new/qtbase/src/plugins/platforms/xcb/xcb-static/xcb-static.pro 2015-03-17 02:10:15.485922059 +0000
+--- old/qtbase/src/plugins/platforms/xcb/xcb-static/xcb-static.pro
++++ new/qtbase/src/plugins/platforms/xcb/xcb-static/xcb-static.pro
@@ -9,7 +9,8 @@
XCB_DIR = ../../../../3rdparty/xcb
@@ -31,8 +31,8 @@
QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB
QMAKE_CFLAGS += $$QMAKE_CFLAGS_XCB
---- old/qtbase/src/plugins/platforms/xcb/xcb-plugin.pro 2015-07-24 16:02:59.530038830 -0400
-+++ new/qtbase/src/plugins/platforms/xcb/xcb-plugin.pro 2015-07-24 16:01:22.106037459 -0400
+--- old/qtbase/src/plugins/platforms/xcb/xcb-plugin.pro
++++ new/qtbase/src/plugins/platforms/xcb/xcb-plugin.pro
@@ -6,6 +6,13 @@
qxcbmain.cpp
OTHER_FILES += xcb.json README
diff --git a/depends/patches/qt/fix_qt_pkgconfig.patch b/depends/patches/qt/fix_qt_pkgconfig.patch
index 3772db4f8b..34302a9f2d 100644
--- a/depends/patches/qt/fix_qt_pkgconfig.patch
+++ b/depends/patches/qt/fix_qt_pkgconfig.patch
@@ -1,6 +1,6 @@
---- old/qtbase/mkspecs/features/qt_module.prf 2016-03-17 02:06:42.705930685 +0000
-+++ new/qtbase/mkspecs/features/qt_module.prf 2016-03-17 02:06:42.705930685 +0000
-@@ -244,7 +244,7 @@
+--- old/qtbase/mkspecs/features/qt_module.prf
++++ new/qtbase/mkspecs/features/qt_module.prf
+@@ -245,7 +245,7 @@
load(qt_targets)
# this builds on top of qt_common
diff --git a/depends/patches/qt/mac-qmake.conf b/depends/patches/qt/mac-qmake.conf
index a6d0070cca..ca70d30b15 100644
--- a/depends/patches/qt/mac-qmake.conf
+++ b/depends/patches/qt/mac-qmake.conf
@@ -1,6 +1,5 @@
MAKEFILE_GENERATOR = UNIX
CONFIG += app_bundle incremental global_init_link_order lib_version_first plugin_no_soname absolute_library_soname
-DEFINES += QT_NO_PRINTER QT_NO_PRINTDIALOG
QMAKE_INCREMENTAL_STYLE = sublib
include(../common/macx.conf)
include(../common/gcc-base-mac.conf)
@@ -11,14 +10,14 @@ QMAKE_XCODE_VERSION=4.3
QMAKE_XCODE_DEVELOPER_PATH=/Developer
QMAKE_MACOSX_DEPLOYMENT_TARGET = $${MAC_MIN_VERSION}
QMAKE_MAC_SDK=macosx
-QMAKE_MAC_SDK.macosx.path = $${MAC_SDK_PATH}
+QMAKE_MAC_SDK.macosx.Path = $${MAC_SDK_PATH}
QMAKE_MAC_SDK.macosx.platform_name = macosx
-QMAKE_MAC_SDK.macosx.version = $${MAC_SDK_VERSION}
-QMAKE_MAC_SDK.macosx.platform_path = /phony
-QMAKE_CFLAGS += -target $${MAC_TARGET}
-QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_CFLAGS
-QMAKE_CXXFLAGS += $$QMAKE_CFLAGS
-QMAKE_LFLAGS += -target $${MAC_TARGET} -mlinker-version=$${MAC_LD64_VERSION}
+QMAKE_MAC_SDK.macosx.SDKVersion = $${MAC_SDK_VERSION}
+QMAKE_MAC_SDK.macosx.PlatformPath = /phony
+!host_build: QMAKE_CFLAGS += -target $${MAC_TARGET}
+!host_build: QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_CFLAGS
+!host_build: QMAKE_CXXFLAGS += $$QMAKE_CFLAGS
+!host_build: QMAKE_LFLAGS += -target $${MAC_TARGET} -mlinker-version=$${MAC_LD64_VERSION}
QMAKE_AR = $${CROSS_COMPILE}ar cq
QMAKE_RANLIB=$${CROSS_COMPILE}ranlib
QMAKE_LIBTOOL=$${CROSS_COMPILE}libtool
diff --git a/depends/patches/qt/mingw-uuidof.patch b/depends/patches/qt/mingw-uuidof.patch
index 975366e612..fb21923c8c 100644
--- a/depends/patches/qt/mingw-uuidof.patch
+++ b/depends/patches/qt/mingw-uuidof.patch
@@ -1,6 +1,6 @@
---- old/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp 2015-06-20 17:40:20.956781548 -0400
-+++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp 2015-06-20 17:29:32.052772416 -0400
-@@ -69,7 +69,7 @@
+--- old/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp
++++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp
+@@ -77,7 +77,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <windowsx.h>
@@ -9,8 +9,8 @@
# include <comdef.h>
#endif
-@@ -762,7 +762,7 @@
- HWND_MESSAGE, NULL, (HINSTANCE)GetModuleHandle(0), NULL);
+@@ -814,7 +814,7 @@
+ HWND_MESSAGE, NULL, static_cast<HINSTANCE>(GetModuleHandle(0)), NULL);
}
-#ifndef Q_OS_WINCE
@@ -18,16 +18,16 @@
// Re-engineered from the inline function _com_error::ErrorMessage().
// We cannot use it directly since it uses swprintf_s(), which is not
// present in the MSVCRT.DLL found on Windows XP (QTBUG-35617).
-@@ -781,7 +781,7 @@
- return QStringLiteral("IDispatch error #") + QString::number(wCode);
- return QStringLiteral("Unknown error 0x0") + QString::number(comError.Error(), 16);
+@@ -833,7 +833,7 @@
+ return QString::asprintf("IDispatch error #%u", uint(wCode));
+ return QString::asprintf("Unknown error 0x0%x", uint(comError.Error()));
}
-#endif // !Q_OS_WINCE
+#endif // !defined(Q_OS_WINCE) && (!defined(USE___UUIDOF) || (defined(USE___UUIDOF) && USE___UUIDOF == 1))
/*!
\brief Common COM error strings.
-@@ -846,12 +846,12 @@
+@@ -901,12 +901,12 @@
default:
break;
}
diff --git a/depends/patches/qt/pidlist_absolute.patch b/depends/patches/qt/pidlist_absolute.patch
index 0b49c050dc..c792824179 100644
--- a/depends/patches/qt/pidlist_absolute.patch
+++ b/depends/patches/qt/pidlist_absolute.patch
@@ -1,7 +1,7 @@
diff -dur old/qtbase/src/plugins/platforms/windows/qwindowscontext.h new/qtbase/src/plugins/platforms/windows/qwindowscontext.h
---- old/qtbase/src/plugins/platforms/windows/qwindowscontext.h 2015-06-29 22:04:40.000000000 +0200
-+++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.h 2015-11-01 12:55:59.751234846 +0100
-@@ -124,10 +124,18 @@
+--- old/qtbase/src/plugins/platforms/windows/qwindowscontext.h
++++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.h
+@@ -136,10 +136,18 @@
inline void init();
typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **);
@@ -21,9 +21,9 @@ diff -dur old/qtbase/src/plugins/platforms/windows/qwindowscontext.h new/qtbase/
SHCreateItemFromParsingName sHCreateItemFromParsingName;
SHGetKnownFolderIDList sHGetKnownFolderIDList;
diff -dur old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
---- old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp 2015-06-29 22:04:40.000000000 +0200
-+++ new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp 2015-11-01 13:41:09.503149772 +0100
-@@ -1008,7 +1008,11 @@
+--- old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
++++ new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+@@ -1016,7 +1016,11 @@
qWarning() << __FUNCTION__ << ": Invalid CLSID: " << url.path();
return Q_NULLPTR;
}
diff --git a/depends/patches/qt46/stlfix.patch b/depends/patches/qt46/stlfix.patch
deleted file mode 100644
index f8f6fb04b0..0000000000
--- a/depends/patches/qt46/stlfix.patch
+++ /dev/null
@@ -1,10 +0,0 @@
---- old/config.tests/unix/stl/stltest.cpp 2011-06-23 03:45:23.000000000 -0400
-+++ new/config.tests/unix/stl/stltest.cpp 2014-08-28 00:54:04.154837604 -0400
-@@ -49,6 +49,7 @@
- #include <vector>
- #include <algorithm>
- #include <iostream>
-+#include <cstddef>
-
- // something mean to see if the compiler and C++ standard lib are good enough
- template<class K, class T>
diff --git a/depends/patches/zeromq/9114d3957725acd34aa8b8d011585812f3369411.patch b/depends/patches/zeromq/9114d3957725acd34aa8b8d011585812f3369411.patch
new file mode 100644
index 0000000000..f704b3d94f
--- /dev/null
+++ b/depends/patches/zeromq/9114d3957725acd34aa8b8d011585812f3369411.patch
@@ -0,0 +1,22 @@
+From 9114d3957725acd34aa8b8d011585812f3369411 Mon Sep 17 00:00:00 2001
+From: Jeroen Ooms <jeroenooms@gmail.com>
+Date: Tue, 20 Oct 2015 13:10:38 +0200
+Subject: [PATCH] enable static libraries on mingw
+
+---
+ configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index 393505b..e92131a 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -265,7 +265,7 @@ case "${host_os}" in
+ libzmq_dso_visibility="no"
+
+ if test "x$enable_static" = "xyes"; then
+- AC_MSG_ERROR([Building static libraries is not supported under MinGW32])
++ CPPFLAGS="-DZMQ_STATIC"
+ fi
+
+ # Set FD_SETSIZE to 1024 \ No newline at end of file
diff --git a/depends/patches/zeromq/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch b/depends/patches/zeromq/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch
new file mode 100644
index 0000000000..9aff2c179a
--- /dev/null
+++ b/depends/patches/zeromq/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch
@@ -0,0 +1,22 @@
+From 9e6745c12e0b100cd38acecc16ce7db02905e27c Mon Sep 17 00:00:00 2001
+From: David Millard <dmillard10@gmail.com>
+Date: Tue, 10 May 2016 13:53:53 -0700
+Subject: [PATCH] Fix autotools for static MinGW builds
+
+---
+ configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index 5a0fa14..def6ea7 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -259,7 +259,7 @@ case "${host_os}" in
+ libzmq_dso_visibility="no"
+
+ if test "x$enable_static" = "xyes"; then
+- CPPFLAGS="-DZMQ_STATIC"
++ CPPFLAGS="-DZMQ_STATIC $CPPFLAGS"
+ fi
+
+ # Set FD_SETSIZE to 1024 \ No newline at end of file
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000000..38498103bb
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1 @@
+Doxyfile
diff --git a/doc/Doxyfile b/doc/Doxyfile
deleted file mode 100644
index 428fba98e1..0000000000
--- a/doc/Doxyfile
+++ /dev/null
@@ -1,1752 +0,0 @@
-# Doxyfile 1.7.4
-
-# !!! Invoke doxygen from project root using:
-# doxygen doc/Doxyfile
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
-
-DOXYFILE_ENCODING = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
-
-PROJECT_NAME = Bitcoin
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-PROJECT_NUMBER = 0.12.99
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer
-# a quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF = "P2P Digital Currency"
-
-# With the PROJECT_LOGO tag one can specify an logo or icon that is
-# included in the documentation. The maximum height of the logo should not
-# exceed 55 pixels and the maximum width should not exceed 200 pixels.
-# Doxygen will copy the logo to the output directory.
-
-PROJECT_LOGO = doc/bitcoin_logo_doxygen.png
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY = doc/doxygen
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
-
-CREATE_SUBDIRS = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
-
-OUTPUT_LANGUAGE = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF = "The $name class" \
- "The $name widget" \
- "The $name file" \
- is \
- provides \
- specifies \
- contains \
- represents \
- a \
- an \
- the
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-
-INLINE_INHERITED_MEMB = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
-
-STRIP_FROM_PATH =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
-
-JAVADOC_AUTOBRIEF = YES
-
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
-
-QT_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
-
-INHERIT_DOCS = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
-
-SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE = 8
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n in the value part of an alias to insert newlines.
-
-ALIASES =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C = NO
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
-
-OPTIMIZE_FOR_FORTRAN = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
-
-OPTIMIZE_OUTPUT_VHDL = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
-
-EXTENSION_MAPPING =
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-
-BUILTIN_STL_SUPPORT = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-
-CPP_CLI_SUPPORT = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
-
-SIP_SUPPORT = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
-
-IDL_PROPERTY_SUPPORT = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-
-SUBGROUPING = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
-# unions are shown inside the group in which they are included (e.g. using
-# @ingroup) instead of on a separate page (for HTML and Man pages) or
-# section (for LaTeX and RTF).
-
-INLINE_GROUPED_CLASSES = NO
-
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-
-TYPEDEF_HIDES_STRUCT = NO
-
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
-
-SYMBOL_CACHE_SIZE = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
-EXTRACT_PRIVATE = YES
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
-EXTRACT_STATIC = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespaces are hidden.
-
-EXTRACT_ANON_NSPACES = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
-
-FORCE_LOCAL_INCLUDES = NO
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
-SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
-
-SORT_GROUP_NAMES = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
-# do proper type resolution of all parameters of a function it will reject a
-# match between the prototype and the implementation of a member function even
-# if there is only one candidate or it is obvious which candidate to choose
-# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
-# will still accept a match between prototype and implementation in such cases.
-
-STRICT_PROTO_MATCHING = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
-GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
-
-GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES = YES
-
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES = NO
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
-
-SHOW_FILES = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page. This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
-
-SHOW_NAMESPACES = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
-
-FILE_VERSION_FILTER =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. The create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
-
-LAYOUT_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
-WARNINGS = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR = YES
-
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
-
-WARN_NO_PARAMDOC = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
-INPUT = src
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
-
-INPUT_ENCODING = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.for *.vhd *.vhdl
-
-FILE_PATTERNS = *.c \
- *.cc \
- *.cxx \
- *.cpp \
- *.c++ \
- *.d \
- *.java \
- *.ii \
- *.ixx \
- *.ipp \
- *.i++ \
- *.inl \
- *.h \
- *.hh \
- *.hxx \
- *.hpp \
- *.h++ \
- *.idl \
- *.odl \
- *.cs \
- *.php \
- *.php3 \
- *.inc \
- *.m \
- *.mm \
- *.dox \
- *.py \
- *.f90 \
- *.f \
- *.for \
- *.vhd \
- *.vhdl
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
-RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
-EXCLUDE = src/leveldb src/json src/test /src/qt/test
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-
-EXCLUDE_SYMBOLS = boost google
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-EXAMPLE_PATTERNS = *
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output. If FILTER_PATTERNS is specified, this tag will be
-# ignored.
-
-INPUT_FILTER =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty or if
-# non of the patterns match the file name, INPUT_FILTER is applied.
-
-FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
-# and it is also possible to disable source filtering for a specific pattern
-# using *.ext= (so without naming a filter). This option only has effect when
-# FILTER_SOURCE_FILES is enabled.
-
-FILTER_SOURCE_PATTERNS =
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
-
-SOURCE_BROWSER = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-
-REFERENCES_RELATION = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code. Otherwise they will link to the documentation.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
-
-USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX = YES
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header. Note that when using a custom header you are responsible
-# for the proper inclusion of any scripts and style sheets that doxygen
-# needs, which is dependent on the configuration options used.
-# It is adviced to generate a default header using "doxygen -w html
-# header.html footer.html stylesheet.css YourConfigFile" and then modify
-# that header. Note that the header is subject to change so you typically
-# have to redo this when upgrading to a newer version of doxygen or when
-# changing the value of configuration settings such as GENERATE_TREEVIEW!
-
-HTML_HEADER =
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
-HTML_FOOTER =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
-
-HTML_STYLESHEET =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that
-# the files will be copied as-is; there are no commands or markers available.
-
-HTML_EXTRA_FILES =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the stylesheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
-
-HTML_COLORSTYLE_HUE = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
-
-HTML_COLORSTYLE_SAT = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
-
-HTML_COLORSTYLE_GAMMA = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
-
-HTML_TIMESTAMP = YES
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded. For this to work a browser that supports
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
-
-HTML_DYNAMIC_SECTIONS = NO
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-
-GENERATE_DOCSET = NO
-
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
-
-DOCSET_FEEDNAME = "Doxygen generated docs"
-
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
-
-DOCSET_BUNDLE_ID = org.doxygen.Project
-
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
-
-DOCSET_PUBLISHER_NAME = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output directory.
-
-CHM_FILE =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
-
-CHM_INDEX_ENCODING =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
-
-GENERATE_QHP = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
-
-QCH_FILE =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
-
-QHP_NAMESPACE = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
-
-QHP_VIRTUAL_FOLDER = doc
-
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
-
-QHP_CUST_FILTER_NAME =
-
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
-
-QHP_CUST_FILTER_ATTRS =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
-
-QHP_SECT_FILTER_ATTRS =
-
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
-
-QHG_LOCATION =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-# will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
-
-GENERATE_ECLIPSEHELP = NO
-
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
-
-ECLIPSE_DOC_ID = org.doxygen.Project
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-
-DISABLE_INDEX = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
-# (range [0,1..20]) that doxygen will group on one line in the generated HTML
-# documentation. Note that a value of 0 will completely suppress the enum
-# values from appearing in the overview section.
-
-ENUM_VALUES_PER_LINE = 4
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-
-GENERATE_TREEVIEW = NO
-
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
-
-USE_INLINE_TREES = NO
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
-TREEVIEW_WIDTH = 250
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
-
-EXT_LINKS_IN_WINDOW = NO
-
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
-
-FORMULA_FONTSIZE = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
-
-FORMULA_TRANSPARENT = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
-# (see http://www.mathjax.org) which uses client side Javascript for the
-# rendering instead of using prerendered bitmaps. Use this if you do not
-# have LaTeX installed or if you want to formulas look prettier in the HTML
-# output. When enabled you also need to install MathJax separately and
-# configure the path to it using the MATHJAX_RELPATH option.
-
-USE_MATHJAX = NO
-
-# When MathJax is enabled you need to specify the location relative to the
-# HTML output directory using the MATHJAX_RELPATH option. The destination
-# directory should contain the MathJax.js script. For instance, if the mathjax
-# directory is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the
-# mathjax.org site, so you can quickly see the result without installing
-# MathJax, but it is strongly recommended to install a local copy of MathJax
-# before deployment.
-
-MATHJAX_RELPATH = http://www.mathjax.org/mathjax
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
-
-SEARCHENGINE = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvantages are that it is more difficult to setup
-# and does not have live searching capabilities.
-
-SERVER_BASED_SEARCH = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
-
-LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, letter, legal and
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE = a4
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
-# the generated latex document. The footer should contain everything after
-# the last chapter. If it is left blank doxygen will generate a
-# standard footer. Notice: only use this tag if you know what you are doing!
-
-LATEX_FOOTER =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS = YES
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
-USE_PDFLATEX = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-
-LATEX_HIDE_INDICES = NO
-
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
-
-LATEX_SOURCE_CODE = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader. This is useful
-# if you want to understand what is going on. On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# pointed to by INCLUDE_PATH will be searched when a #include is found.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
-INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
-
-PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition that
-# overrules the definition found in the source code.
-
-EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all references to function-like macros
-# that are alone on a line, have an all uppercase name, and do not end with a
-# semicolon, because these will confuse the parser if not removed.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
-ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-
-EXTERNAL_GROUPS = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
-
-CLASS_DIAGRAMS = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT = YES
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
-
-DOT_NUM_THREADS = 0
-
-# By default doxygen will write a font called Helvetica to the output
-# directory and reference it in all dot files that doxygen generates.
-# When you want a differently looking font you can specify the font name
-# using DOT_FONTNAME. You need to make sure dot is able to find the font,
-# which can be done by putting it in a standard location or by setting the
-# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
-# containing the font.
-
-DOT_FONTNAME = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
-
-DOT_FONTSIZE = 10
-
-# By default doxygen will tell dot to use the output directory to look for the
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a
-# different font using DOT_FONTNAME you can set the path where dot
-# can find it using this tag.
-
-DOT_FONTPATH =
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH = YES
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
-
-GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-
-UML_LOOK = NO
-
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS = NO
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-
-INCLUDE_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
-
-CALL_GRAPH = YES
-
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
-
-CALLER_GRAPH = YES
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY = YES
-
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-
-DIRECTORY_GRAPH = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are svg, png, jpg, or gif.
-# If left blank png will be used.
-
-DOT_IMAGE_FORMAT = svg
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-
-DOTFILE_DIRS =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the
-# \mscfile command).
-
-MSCFILE_DIRS =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-
-DOT_GRAPH_MAX_NODES = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-
-MAX_DOT_GRAPH_DEPTH = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
-
-DOT_TRANSPARENT = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
-
-DOT_MULTI_TARGETS = NO
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-
-DOT_CLEANUP = YES
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 0000000000..58c65fb7e2
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,2460 @@
+# Doxyfile 1.8.12
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "Bitcoin Core"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = @PACKAGE_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "P2P Digital Currency"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO = doc/bitcoin_logo_doxygen.png
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.vhd \
+ *.vhdl
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = src/leveldb \
+ src/json \
+ src/test \
+ src/qt/test
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS = boost \
+ google
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.bitcoin.Bitcoin-Core
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.bitcoin.Bitcoin-Core
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/doc/README.md b/doc/README.md
index c30f29452b..275ae67e54 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -1,9 +1,11 @@
-Bitcoin Core 0.12.99
-=====================
+Bitcoin Core
+=============
Setup
---------------------
-[Bitcoin Core](http://bitcoin.org/en/download) is the original Bitcoin client and it builds the backbone of the network. However, it downloads and stores the entire history of Bitcoin transactions (which is currently several GBs); depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more.
+Bitcoin Core is the original Bitcoin client and it builds the backbone of the network. It downloads and, by default, stores the entire history of Bitcoin transactions (which is currently more than 100 GBs); depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more.
+
+To download Bitcoin Core, visit [bitcoincore.org](https://bitcoincore.org/en/releases/).
Running
---------------------
@@ -46,13 +48,12 @@ Development
The Bitcoin repo's [root README](/README.md) contains relevant information on the development process and automated testing.
- [Developer Notes](developer-notes.md)
-- [Multiwallet Qt Development](multiwallet-qt.md)
- [Release Notes](release-notes.md)
- [Release Process](release-process.md)
- [Source Code Documentation (External Link)](https://dev.visucore.com/bitcoin/doxygen/)
- [Translation Process](translation_process.md)
- [Translation Strings Policy](translation_strings_policy.md)
-- [Unit Tests](unit-tests.md)
+- [Travis CI](travis-ci.md)
- [Unauthenticated REST Interface](REST-interface.md)
- [Shared Libraries](shared-libraries.md)
- [BIPS](bips.md)
@@ -67,11 +68,14 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th
### Miscellaneous
- [Assets Attribution](assets-attribution.md)
- [Files](files.md)
+- [Fuzz-testing](fuzzing.md)
+- [Reduce Traffic](reduce-traffic.md)
- [Tor Support](tor.md)
- [Init Scripts (systemd/upstart/openrc)](init.md)
+- [ZMQ](zmq.md)
License
---------------------
-Distributed under the [MIT software license](http://www.opensource.org/licenses/mit-license.php).
+Distributed under the [MIT software license](/COPYING).
This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](https://www.openssl.org/). This product includes
cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard.
diff --git a/doc/README_osx.md b/doc/README_osx.md
index aed3cd97e1..2a4460478c 100644
--- a/doc/README_osx.md
+++ b/doc/README_osx.md
@@ -22,7 +22,7 @@ These tools inject timestamps by default, which produce non-deterministic
binaries. The ZERO_AR_DATE environment variable is used to disable that.
This version of cctools has been patched to use the current version of clang's
-headers and and its libLTO.so rather than those from llvmgcc, as it was
+headers and its libLTO.so rather than those from llvmgcc, as it was
originally done in toolchain4.
To complicate things further, all builds must target an Apple SDK. These SDKs
@@ -36,11 +36,26 @@ Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.1
```
Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file.
-To create a tarball suitable for Gitian input, mount the dmg in OS X, then create it with:
+To create a tarball suitable for Gitian input, there are two options:
+
+Using Mac OS X, you can mount the dmg, and then create it with:
```
+ $ hdiutil attach Xcode_7.3.1.dmg
$ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk
```
+Alternatively, you can use 7zip and SleuthKit to extract the files one by one.
+The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure
+the dmg file is in the current directory, and then run the script. You may wish
+to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when
+you've confirmed the extraction succeeded.
+
+```bash
+apt-get install p7zip-full sleuthkit
+contrib/macdeploy/extract-osx-sdk.sh
+rm -rf 5.hfs MacOSX10.11.sdk
+```
+
The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries
which are created using these tools. The build process has been designed to
avoid including the SDK's files in Gitian's outputs. All interim tarballs are
diff --git a/doc/README_windows.txt b/doc/README_windows.txt
index 2d1c4503c9..07d61b3bda 100644
--- a/doc/README_windows.txt
+++ b/doc/README_windows.txt
@@ -1,5 +1,5 @@
-Bitcoin Core 0.12.99
-=====================
+Bitcoin Core
+=============
Intro
-----
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index bf669235e3..7fbb174030 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -3,6 +3,8 @@ Unauthenticated REST Interface
The REST API can be enabled with the `-rest` option.
+The interface runs on the same port as the JSON-RPC interface, by default port 8332 for mainnet and port 18332 for testnet.
+
Supported API
-------------
diff --git a/doc/bips.md b/doc/bips.md
index 039d5114fd..bc8dcb6fb3 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -20,10 +20,16 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.13.0**):
* [`BIP 66`](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki): The strict DER rules and associated version 3 blocks have been implemented since **v0.10.0** ([PR #5713](https://github.com/bitcoin/bitcoin/pull/5713)).
* [`BIP 68`](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki): Sequence locks have been implemented as of **v0.12.1** ([PR #7184](https://github.com/bitcoin/bitcoin/pull/7184)), and have been activated since *block 419328*.
* [`BIP 70`](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki) [`71`](https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki) [`72`](https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki): Payment Protocol support has been available in Bitcoin Core GUI since **v0.9.0** ([PR #5216](https://github.com/bitcoin/bitcoin/pull/5216)).
+* [`BIP 90`](https://github.com/bitcoin/bips/blob/master/bip-0090.mediawiki): Trigger mechanism for activation of BIPs 34, 65, and 66 has been simplified to block height checks since **v0.14.0** ([PR #8391](https://github.com/bitcoin/bitcoin/pull/8391)).
* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)).
* [`BIP 112`](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki): The CHECKSEQUENCEVERIFY opcode has been implemented since **v0.12.1** ([PR #7524](https://github.com/bitcoin/bitcoin/pull/7524)) and has been activated since *block 419328*.
* [`BIP 113`](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki): Median time past lock-time calculations have been implemented since **v0.12.1** ([PR #6566](https://github.com/bitcoin/bitcoin/pull/6566)) and have been activated since *block 419328*.
* [`BIP 125`](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki): Opt-in full replace-by-fee signaling honoured in mempool and mining as of **v0.12.0** ([PR 6871](https://github.com/bitcoin/bitcoin/pull/6871)).
* [`BIP 130`](https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki): direct headers announcement is negotiated with peer versions `>=70012` as of **v0.12.0** ([PR 6494](https://github.com/bitcoin/bitcoin/pull/6494)).
* [`BIP 133`](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki): feefilter messages are respected and sent for peer versions `>=70013` as of **v0.13.0** ([PR 7542](https://github.com/bitcoin/bitcoin/pull/7542)).
+* [`BIP 141`](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki): Segregated Witness (Consensus Layer) as of **v0.13.0** ([PR 8149](https://github.com/bitcoin/bitcoin/pull/8149)), and defined for mainnet as of **v0.13.1** ([PR 8937](https://github.com/bitcoin/bitcoin/pull/8937)).
+* [`BIP 143`](https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki): Transaction Signature Verification for Version 0 Witness Program as of **v0.13.0** ([PR 8149](https://github.com/bitcoin/bitcoin/pull/8149)) and defined for mainnet as of **v0.13.1** ([PR 8937](https://github.com/bitcoin/bitcoin/pull/8937)).
+* [`BIP 144`](https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki): Segregated Witness as of **0.13.0** ([PR 8149](https://github.com/bitcoin/bitcoin/pull/8149)).
+* [`BIP 145`](https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki): getblocktemplate updates for Segregated Witness as of **v0.13.0** ([PR 8149](https://github.com/bitcoin/bitcoin/pull/8149)).
+* [`BIP 147`](https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki): NULLDUMMY softfork as of **v0.13.1** ([PR 8636](https://github.com/bitcoin/bitcoin/pull/8636) and [PR 8937](https://github.com/bitcoin/bitcoin/pull/8937)).
* [`BIP 152`](https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki): Compact block transfer and related optimizations are used as of **v0.13.0** ([PR 8068](https://github.com/bitcoin/bitcoin/pull/8068)).
diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md
index d923301467..f4a9826d80 100644
--- a/doc/build-openbsd.md
+++ b/doc/build-openbsd.md
@@ -1,6 +1,6 @@
OpenBSD build guide
======================
-(updated for OpenBSD 5.7)
+(updated for OpenBSD 6.0)
This guide describes how to build bitcoind and command-line utilities on OpenBSD.
@@ -15,11 +15,10 @@ Run the following as root to install the base dependencies for building:
pkg_add gmake libtool libevent
pkg_add autoconf # (select highest version, e.g. 2.69)
pkg_add automake # (select highest version, e.g. 1.15)
-pkg_add python # (select version 2.7.x, not 3.x)
-ln -sf /usr/local/bin/python2.7 /usr/local/bin/python2
+pkg_add python # (select highest version, e.g. 3.5)
```
-The default C++ compiler that comes with OpenBSD 5.7 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core. It is possible to patch it up to compile, but with the planned transition to C++11 this is a losing battle. So here we will be installing a newer compiler.
+The default C++ compiler that comes with OpenBSD 5.9 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core, primarily as it has no C++11 support, but even before there were issues. So here we will be installing a newer compiler.
GCC
-------
@@ -27,7 +26,7 @@ GCC
You can install a newer version of gcc with:
```bash
-pkg_add g++ # (select newest 4.x version, e.g. 4.9.2)
+pkg_add g++ # (select newest 4.x version, e.g. 4.9.3)
```
This compiler will not overwrite the system compiler, it will be installed as `egcc` and `eg++` in `/usr/local/bin`.
@@ -49,18 +48,15 @@ BOOST_PREFIX="${BITCOIN_ROOT}/boost"
mkdir -p $BOOST_PREFIX
# Fetch the source and verify that it is not tampered with
-wget http://heanet.dl.sourceforge.net/project/boost/boost/1.59.0/boost_1_59_0.tar.bz2
-echo '727a932322d94287b62abb1bd2d41723eec4356a7728909e38adb65ca25241ca boost_1_59_0.tar.bz2' | sha256 -c
-# MUST output: (SHA256) boost_1_59_0.tar.bz2: OK
-tar -xjf boost_1_59_0.tar.bz2
+curl -o boost_1_61_0.tar.bz2 http://heanet.dl.sourceforge.net/project/boost/boost/1.61.0/boost_1_61_0.tar.bz2
+echo 'a547bd06c2fd9a71ba1d169d9cf0339da7ebf4753849a8f7d6fdb8feee99b640 boost_1_61_0.tar.bz2' | sha256 -c
+# MUST output: (SHA256) boost_1_61_0.tar.bz2: OK
+tar -xjf boost_1_61_0.tar.bz2
-# Boost 1.59 needs two small patches for OpenBSD
-cd boost_1_59_0
+# Boost 1.61 needs one small patch for OpenBSD
+cd boost_1_61_0
# Also here: https://gist.githubusercontent.com/laanwj/bf359281dc319b8ff2e1/raw/92250de8404b97bb99d72ab898f4a8cb35ae1ea3/patch-boost_test_impl_execution_monitor_ipp.patch
patch -p0 < /usr/ports/devel/boost/patches/patch-boost_test_impl_execution_monitor_ipp
-# https://github.com/boostorg/filesystem/commit/90517e459681790a091566dce27ca3acabf9a70c
-sed 's/__OPEN_BSD__/__OpenBSD__/g' < libs/filesystem/src/path.cpp > libs/filesystem/src/path.cpp.tmp
-mv libs/filesystem/src/path.cpp.tmp libs/filesystem/src/path.cpp
# Build w/ minimum configuration necessary for bitcoin
echo 'using gcc : : eg++ : <cxxflags>"-fvisibility=hidden -fPIC" <linkflags>"" <archiver>"ar" <striper>"strip" <ranlib>"ranlib" <rc>"" : ;' > user-config.jam
@@ -84,7 +80,7 @@ BDB_PREFIX="${BITCOIN_ROOT}/db4"
mkdir -p $BDB_PREFIX
# Fetch the source and verify that it is not tampered with
-wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
+curl -o db-4.8.30.NC.tar.gz 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
echo '12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz' | sha256 -c
# MUST output: (SHA256) db-4.8.30.NC.tar.gz: OK
tar -xzf db-4.8.30.NC.tar.gz
@@ -93,9 +89,25 @@ tar -xzf db-4.8.30.NC.tar.gz
cd db-4.8.30.NC/build_unix/
# Note: Do a static build so that it can be embedded into the executable, instead of having to find a .so at runtime
../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX CC=egcc CXX=eg++ CPP=ecpp
-make install
+make install # do NOT use -jX, this is broken
```
+### Resource limits
+
+The standard ulimit restrictions in OpenBSD are very strict:
+
+ data(kbytes) 1572864
+
+This is, unfortunately, no longer enough to compile some `.cpp` files in the project,
+at least with gcc 4.9.3 (see issue https://github.com/bitcoin/bitcoin/issues/6658).
+If your user is in the `staff` group the limit can be raised with:
+
+ ulimit -d 3000000
+
+The change will only affect the current shell and processes spawned by it. To
+make the change system-wide, change `datasize-cur` and `datasize-max` in
+`/etc/login.conf`, and reboot.
+
### Building Bitcoin Core
**Important**: use `gmake`, not `make`. The non-GNU `make` will exit with a horrible error.
@@ -112,7 +124,7 @@ To configure with wallet:
```bash
./configure --with-gui=no --with-boost=$BOOST_PREFIX \
CC=egcc CXX=eg++ CPP=ecpp \
- LDFLAGS="-L${BDB_PREFIX}/lib/" CPPFLAGS="-I${BDB_PREFIX}/include/"
+ BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include"
```
To configure without wallet:
@@ -123,13 +135,15 @@ To configure without wallet:
Build and run the tests:
```bash
-gmake
+gmake # can use -jX here for parallelism
gmake check
```
Clang (not currently working)
------------------------------
+WARNING: This is outdated, needs to be updated for OpenBSD 6.0 and re-tried.
+
Using a newer g++ results in linking the new code to a new libstdc++.
Libraries built with the old g++, will still import the old library.
This gives conflicts, necessitating rebuild of all C++ dependencies of the application.
diff --git a/doc/build-osx.md b/doc/build-osx.md
index c9eb4225ab..32d7dbd69e 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -11,12 +11,16 @@ Install the OS X command line tools:
When the popup appears, click `Install`.
-Then install [Homebrew](http://brew.sh).
+Then install [Homebrew](https://brew.sh).
Dependencies
----------------------
- brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf --c++11 qt5 libevent
+ brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf qt libevent
+
+If you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG
+
+ brew install librsvg
NOTE: Building with Qt4 is still supported, however, could result in a broken UI. Building with Qt5 is recommended.
@@ -90,6 +94,6 @@ Uncheck everything except Qt Creator during the installation process.
Notes
-----
-* Tested on OS X 10.7 through 10.11 on 64-bit Intel processors only.
+* Tested on OS X 10.8 through 10.12 on 64-bit Intel processors only.
* Building with downloaded Qt binaries is not officially supported. See the notes in [#7714](https://github.com/bitcoin/bitcoin/issues/7714)
diff --git a/doc/build-unix.md b/doc/build-unix.md
index bd89978cc2..b7eae2a630 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -79,9 +79,12 @@ install necessary parts of boost:
sudo apt-get install libboost-all-dev
-BerkeleyDB is required for the wallet. db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin).
+BerkeleyDB is required for the wallet.
+
+**For Ubuntu only:** db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin).
You can add the repository and install using the following commands:
+ sudo apt-get install software-properties-common
sudo add-apt-repository ppa:bitcoin/bitcoin
sudo apt-get update
sudo apt-get install libdb4.8-dev libdb4.8++-dev
@@ -93,13 +96,13 @@ pass `--with-incompatible-bdb` to configure.
See the section "Disable-wallet mode" to build Bitcoin Core without wallet.
-Optional:
+Optional (see --with-miniupnpc and --enable-upnp-default):
- sudo apt-get install libminiupnpc-dev (see --with-miniupnpc and --enable-upnp-default)
+ sudo apt-get install libminiupnpc-dev
-ZMQ dependencies:
+ZMQ dependencies (provides ZMQ API 4.x):
- sudo apt-get install libzmq3-dev (provides ZMQ API 4.x)
+ sudo apt-get install libzmq3-dev
Dependencies for the GUI: Ubuntu & Debian
-----------------------------------------
@@ -293,9 +296,10 @@ These steps can be performed on, for example, an Ubuntu VM. The depends system
will also work on other Linux distributions, however the commands for
installing the toolchain will be different.
-First install the toolchain:
+Make sure you install the build requirements mentioned above.
+Then, install the toolchain and curl:
- sudo apt-get install g++-arm-linux-gnueabihf
+ sudo apt-get install g++-arm-linux-gnueabihf curl
To build executables for ARM:
@@ -307,3 +311,37 @@ To build executables for ARM:
For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory.
+
+Building on FreeBSD
+--------------------
+
+(Updated as of FreeBSD 11.0)
+
+Clang is installed by default as `cc` compiler, this makes it easier to get
+started than on [OpenBSD](build-openbsd.md). Installing dependencies:
+
+ pkg install autoconf automake libtool pkgconf
+ pkg install boost-libs openssl libevent
+ pkg install gmake
+
+You need to use GNU make (`gmake`) instead of `make`.
+(`libressl` instead of `openssl` will also work)
+
+For the wallet (optional):
+
+ pkg install db5
+
+This will give a warning "configure: WARNING: Found Berkeley DB other
+than 4.8; wallets opened by this build will not be portable!", but as FreeBSD never
+had a binary release, this may not matter. If backwards compatibility
+with 4.8-built Bitcoin Core is needed follow the steps under "Berkeley DB" above.
+
+Then build using:
+
+ ./autogen.sh
+ ./configure --with-incompatible-bdb BDB_CFLAGS="-I/usr/local/include/db5" BDB_LIBS="-L/usr/local/lib -ldb_cxx-5"
+ gmake
+
+*Note on debugging*: The version of `gdb` installed by default is [ancient and considered harmful](https://wiki.freebsd.org/GdbRetirement).
+It is not suitable for debugging a multi-threaded C++ program, not even for getting backtraces. Please install the package `gdb` and
+use the versioned gdb command e.g. `gdb7111`.
diff --git a/doc/build-windows.md b/doc/build-windows.md
index 2b9233d1e1..9549a4b9da 100644
--- a/doc/build-windows.md
+++ b/doc/build-windows.md
@@ -1,13 +1,48 @@
WINDOWS BUILD NOTES
====================
-Some notes on how to build Bitcoin Core for Windows.
+Below are some notes on how to build Bitcoin Core for Windows.
Most developers use cross-compilation from Ubuntu to build executables for
Windows. This is also used to build the release binaries.
-Building on Windows itself is possible (for example using msys / mingw-w64),
-but no one documented the steps to do this. If you are doing this, please contribute them.
+While there are potentially a number of ways to build on Windows (for example using msys / mingw-w64),
+using the Windows Subsystem For Linux is the most straightforward. If you are building with
+another method, please contribute the instructions here for others who are running versions
+of Windows that are not compatible with the Windows Subsystem for Linux.
+
+Compiling with Windows Subsystem For Linux
+-------------------------------------------
+
+With Windows 10, Microsoft has released a new feature named the [Windows
+Subsystem for Linux](https://msdn.microsoft.com/commandline/wsl/about). This
+feature allows you to run a bash shell directly on Windows in an Ubuntu-based
+environment. Within this environment you can cross compile for Windows without
+the need for a separate Linux VM or server.
+
+This feature is not supported in versions of Windows prior to Windows 10 or on
+Windows Server SKUs. In addition, it is available [only for 64-bit versions of
+Windows](https://msdn.microsoft.com/en-us/commandline/wsl/install_guide).
+
+To get the bash shell, you must first activate the feature in Windows.
+
+1. Turn on Developer Mode
+ * Open Settings -> Update and Security -> For developers
+ * Select the Developer Mode radio button
+ * Restart if necessary
+2. Enable the Windows Subsystem for Linux feature
+ * From Start, search for "Turn Windows features on or off" (type 'turn')
+ * Select Windows Subsystem for Linux (beta)
+ * Click OK
+ * Restart if necessary
+3. Complete Installation
+ * Open a cmd prompt and type "bash"
+ * Accept the license
+ * Create a new UNIX user account (this is a separate account from your Windows account)
+
+After the bash shell is active, you can follow the instructions below, starting
+with the "Cross-compilation" section. Compiling the 64-bit version is
+recommended but it is possible to compile the 32-bit version.
Cross-compilation
-------------------
@@ -16,25 +51,54 @@ These steps can be performed on, for example, an Ubuntu VM. The depends system
will also work on other Linux distributions, however the commands for
installing the toolchain will be different.
-First install the toolchains:
+First, install the general dependencies:
+
+ sudo apt-get install build-essential libtool autotools-dev automake pkg-config bsdmainutils curl
+
+A host toolchain (`build-essential`) is necessary because some dependency
+packages (such as `protobuf`) need to build host utilities that are used in the
+build process.
- sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev g++-mingw-w64-x86-64 mingw-w64-x86-64-dev
+## Building for 64-bit Windows
-To build executables for Windows 32-bit:
+To build executables for Windows 64-bit, install the following dependencies:
+
+ sudo apt-get install g++-mingw-w64-x86-64 mingw-w64-x86-64-dev
+
+Then build using:
cd depends
- make HOST=i686-w64-mingw32 -j4
+ make HOST=x86_64-w64-mingw32
cd ..
- ./configure --prefix=`pwd`/depends/i686-w64-mingw32
+ ./autogen.sh # not required when building from tarball
+ CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site ./configure --prefix=/
make
-To build executables for Windows 64-bit:
+## Building for 32-bit Windows
+
+To build executables for Windows 32-bit, install the following dependencies:
+
+ sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev
+
+Then build using:
cd depends
- make HOST=x86_64-w64-mingw32 -j4
+ make HOST=i686-w64-mingw32
cd ..
- ./configure --prefix=`pwd`/depends/x86_64-w64-mingw32
+ ./autogen.sh # not required when building from tarball
+ CONFIG_SITE=$PWD/depends/i686-w64-mingw32/share/config.site ./configure --prefix=/
make
+## Depends system
+
For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory.
+Installation
+-------------
+
+After building using the Windows subsystem it can be useful to copy the compiled
+executables to a directory on the windows drive in the same directory structure
+as they appear in the release `.zip` archive. This can be done in the following
+way. This will install to `c:\workspace\bitcoin`, for example:
+
+ make install DESTDIR=/mnt/c/workspace/bitcoin
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 95c46b05fe..cf860a1bf2 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -4,16 +4,22 @@ Developer Notes
Various coding styles have been used during the history of the codebase,
and the result is not very consistent. However, we're now trying to converge to
a single style, so please use it in new code. Old code will be converted
-gradually.
+gradually and you are encouraged to use the provided
+[clang-format-diff script](/contrib/devtools/README.md#clang-format-diffpy)
+to clean up the patch automatically before submitting a pull request.
+
- Basic rules specified in [src/.clang-format](/src/.clang-format).
- Use a recent clang-format to format automatically using one of the [dev scripts]
- (/contrib/devtools/README.md#clang-formatpy).
- Braces on new lines for namespaces, classes, functions, methods.
- Braces on the same line for everything else.
- 4 space indentation (no tabs) for every block except namespaces.
- - No indentation for public/protected/private or for namespaces.
+ - No indentation for `public`/`protected`/`private` or for `namespace`.
- No extra spaces inside parenthesis; don't do ( this )
- - No space after function names; one space after if, for and while.
+ - No space after function names; one space after `if`, `for` and `while`.
+ - If an `if` only has a single-statement then-clause, it can appear
+ on the same line as the if, without braces. In every other case,
+ braces are required, and the then and else clauses must appear
+ correctly indented on a new line.
+ - `++i` is preferred over `i++`.
Block style example:
```c++
@@ -21,14 +27,18 @@ namespace foo
{
class Class
{
- bool Function(char* psz, int n)
+ bool Function(const std::string& s, int n)
{
// Comment summarising what this section of code does
- for (int i = 0; i < n; i++) {
+ for (int i = 0; i < n; ++i) {
// When something fails, return early
- if (!Something())
- return false;
+ if (!Something()) return false;
...
+ if (SomethingElse()) {
+ DoMore();
+ } else {
+ DoLess();
+ }
}
// Success return is usually at the end
@@ -122,7 +132,7 @@ Run with the -testnet option to run with "play bitcoins" on the test network, if
are testing multi-machine code that needs to operate across the internet.
If you are testing something that can run on one machine, run with the -regtest option.
-In regression test mode, blocks can be created on-demand; see qa/rpc-tests/ for tests
+In regression test mode, blocks can be created on-demand; see test/functional/ for tests
that run in -regtest mode.
**DEBUG_LOCKORDER**
@@ -231,9 +241,9 @@ General Bitcoin Core
- *Rationale*: Makes sure that they pass thorough testing, and that the tester will keep passing
on the master branch. Otherwise all new pull requests will start failing the tests, resulting in
confusion and mayhem
-
+
- *Explanation*: If the test suite is to be updated for a change, this has to
- be done first
+ be done first
Wallet
-------
@@ -242,7 +252,7 @@ Wallet
- *Rationale*: In RPC code that conditionally uses the wallet (such as
`validateaddress`) it is easy to forget that global pointer `pwalletMain`
- can be NULL. See `qa/rpc-tests/disablewallet.py` for functional tests
+ can be NULL. See `test/functional/disablewallet.py` for functional tests
exercising the API with `-disablewallet`
- Include `db_cxx.h` (BerkeleyDB header) only when `ENABLE_WALLET` is set
@@ -330,6 +340,31 @@ Strings and formatting
- *Rationale*: Bitcoin Core uses tinyformat, which is type safe. Leave them out to avoid confusion
+Variable names
+--------------
+
+Although the shadowing warning (`-Wshadow`) is not enabled by default (it prevents issues rising
+from using a different variable with the same name),
+please name variables so that their names do not shadow variables defined in the source code.
+
+E.g. in member initializers, prepend `_` to the argument name shadowing the
+member name:
+
+```c++
+class AddressBookPage
+{
+ Mode mode;
+}
+
+AddressBookPage::AddressBookPage(Mode _mode) :
+ mode(_mode)
+...
+```
+
+When using nested cycles, do not name the inner cycle variable the same as in
+upper cycle etc.
+
+
Threads and synchronization
----------------------------
@@ -381,7 +416,38 @@ GUI
should not interact with the user. That's where View classes come in. The converse also
holds: try to not directly access core data structures from Views.
-Git and github tips
+Subtrees
+----------
+
+Several parts of the repository are subtrees of software maintained elsewhere.
+
+Some of these are maintained by active developers of Bitcoin Core, in which case changes should probably go
+directly upstream without being PRed directly against the project. They will be merged back in the next
+subtree merge.
+
+Others are external projects without a tight relationship with our project. Changes to these should also
+be sent upstream but bugfixes may also be prudent to PR against Bitcoin Core so that they can be integrated
+quickly. Cosmetic changes should be purely taken upstream.
+
+There is a tool in contrib/devtools/git-subtree-check.sh to check a subtree directory for consistency with
+its upstream repository.
+
+Current subtrees include:
+
+- src/leveldb
+ - Upstream at https://github.com/google/leveldb ; Maintained by Google, but open important PRs to Core to avoid delay
+
+- src/libsecp256k1
+ - Upstream at https://github.com/bitcoin-core/secp256k1/ ; actively maintaned by Core contributors.
+
+- src/crypto/ctaes
+ - Upstream at https://github.com/bitcoin-core/ctaes ; actively maintained by Core contributors.
+
+- src/univalue
+ - Upstream at https://github.com/jgarzik/univalue ; report important PRs to Core to avoid delay.
+
+
+Git and GitHub tips
---------------------
- For resolving merge/rebase conflicts, it can be useful to enable diff3 style using
@@ -428,3 +494,76 @@ Git and github tips
This will add an `upstream-pull` remote to your git repository, which can be fetched using `git fetch --all`
or `git fetch upstream-pull`. Afterwards, you can use `upstream-pull/NUMBER/head` in arguments to `git show`,
`git checkout` and anywhere a commit id would be acceptable to see the changes from pull request NUMBER.
+
+RPC interface guidelines
+--------------------------
+
+A few guidelines for introducing and reviewing new RPC interfaces:
+
+- Method naming: use consecutive lower-case names such as `getrawtransaction` and `submitblock`
+
+ - *Rationale*: Consistency with existing interface.
+
+- Argument naming: use snake case `fee_delta` (and not, e.g. camel case `feeDelta`)
+
+ - *Rationale*: Consistency with existing interface.
+
+- Use the JSON parser for parsing, don't manually parse integers or strings from
+ arguments unless absolutely necessary.
+
+ - *Rationale*: Introduces hand-rolled string manipulation code at both the caller and callee sites,
+ which is error prone, and it is easy to get things such as escaping wrong.
+ JSON already supports nested data structures, no need to re-invent the wheel.
+
+ - *Exception*: AmountToValue can parse amounts as string. This was introduced because many JSON
+ parsers and formatters hard-code handling decimal numbers as floating point
+ values, resulting in potential loss of precision. This is unacceptable for
+ monetary values. **Always** use `AmountToValue` and `ValueToAmount` when
+ inputting or outputting monetary values. The only exceptions to this are
+ `prioritisetransaction` and `getblocktemplate` because their interface
+ is specified as-is in BIP22.
+
+- Missing arguments and 'null' should be treated the same: as default values. If there is no
+ default value, both cases should fail in the same way.
+
+ - *Rationale*: Avoids surprises when switching to name-based arguments. Missing name-based arguments
+ are passed as 'null'.
+
+ - *Exception*: Many legacy exceptions to this exist, one of the worst ones is
+ `getbalance` which follows a completely different code path based on the
+ number of arguments. We are still in the process of cleaning these up. Do not introduce
+ new ones.
+
+- Try not to overload methods on argument type. E.g. don't make `getblock(true)` and `getblock("hash")`
+ do different things.
+
+ - *Rationale*: This is impossible to use with `bitcoin-cli`, and can be surprising to users.
+
+ - *Exception*: Some RPC calls can take both an `int` and `bool`, most notably when a bool was switched
+ to a multi-value, or due to other historical reasons. **Always** have false map to 0 and
+ true to 1 in this case.
+
+- Don't forget to fill in the argument names correctly in the RPC command table.
+
+ - *Rationale*: If not, the call can not be used with name-based arguments.
+
+- Set okSafeMode in the RPC command table to a sensible value: safe mode is when the
+ blockchain is regarded to be in a confused state, and the client deems it unsafe to
+ do anything irreversible such as send. Anything that just queries should be permitted.
+
+ - *Rationale*: Troubleshooting a node in safe mode is difficult if half the
+ RPCs don't work.
+
+- Add every non-string RPC argument `(method, idx, name)` to the table `vRPCConvertParams` in `rpc/client.cpp`.
+
+ - *Rationale*: `bitcoin-cli` and the GUI debug console use this table to determine how to
+ convert a plaintext command line to JSON. If the types don't match, the method can be unusable
+ from there.
+
+- A RPC method must either be a wallet method or a non-wallet method. Do not
+ introduce new methods such as `getinfo` and `signrawtransaction` that differ
+ in behavior based on presence of a wallet.
+
+ - *Rationale*: as well as complicating the implementation and interfering
+ with the introduction of multi-wallet, wallet and non-wallet code should be
+ separated to avoid introducing circular dependencies between code units.
diff --git a/doc/files.md b/doc/files.md
index f7eca57dcb..928977143b 100644
--- a/doc/files.md
+++ b/doc/files.md
@@ -10,6 +10,7 @@
* db.log: wallet database log file
* debug.log: contains debug information and general logging generated by bitcoind or bitcoin-qt
* fee_estimates.dat: stores statistics used to estimate minimum transaction fees and priorities required for confirmation; since 0.10.0
+* mempool.dat: dump of the mempool's transactions; since 0.14.0.
* peers.dat: peer IP address database (custom format); since 0.7.0
* wallet.dat: personal wallet (BDB) with keys and transactions
* .cookie: session RPC authentication cookie (written at start when cookie authentication is used, deleted on shutdown): since 0.12.0
diff --git a/doc/fuzzing.md b/doc/fuzzing.md
new file mode 100644
index 0000000000..bf3ad17861
--- /dev/null
+++ b/doc/fuzzing.md
@@ -0,0 +1,66 @@
+Fuzz-testing Bitcoin Core
+==========================
+
+A special test harness `test_bitcoin_fuzzy` is provided to provide an easy
+entry point for fuzzers and the like. In this document we'll describe how to
+use it with AFL.
+
+Building AFL
+-------------
+
+It is recommended to always use the latest version of afl:
+```
+wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
+tar -zxvf afl-latest.tgz
+cd afl-<version>
+make
+export AFLPATH=$PWD
+```
+
+Instrumentation
+----------------
+
+To build Bitcoin Core using AFL instrumentation (this assumes that the
+`AFLPATH` was set as above):
+```
+./configure --disable-ccache --disable-shared --enable-tests CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++
+export AFL_HARDEN=1
+cd src/
+make test/test_bitcoin_fuzzy
+```
+We disable ccache because we don't want to pollute the ccache with instrumented
+objects, and similarly don't want to use non-instrumented cached objects linked
+in.
+
+Preparing fuzzing
+------------------
+
+AFL needs an input directory with examples, and an output directory where it
+will place examples that it found. These can be anywhere in the file system,
+we'll define environment variables to make it easy to reference them.
+
+```
+mkdir inputs
+AFLIN=$PWD/inputs
+mkdir outputs
+AFLOUT=$PWD/outputs
+```
+
+Example inputs are available from:
+
+- https://download.visucore.com/bitcoin/bitcoin_fuzzy_in.tar.xz
+- http://strateman.ninja/fuzzing.tar.xz
+
+Extract these (or other starting inputs) into the `inputs` directory before starting fuzzing.
+
+Fuzzing
+--------
+
+To start the actual fuzzing use:
+```
+$AFLPATH/afl-fuzz -i ${AFLIN} -o ${AFLOUT} -m52 -- test/test_bitcoin_fuzzy
+```
+
+You may have to change a few kernel parameters to test optimally - `afl-fuzz`
+will print an error and suggestion if so.
+
diff --git a/doc/gitian-building.md b/doc/gitian-building.md
index 7796a5fc9c..c2f55b5796 100644
--- a/doc/gitian-building.md
+++ b/doc/gitian-building.md
@@ -55,7 +55,7 @@ In the VirtualBox GUI click "New" and choose the following parameters in the wiz
![](gitian-building/create_vm_memsize.png)
-- Memory Size: at least 1024MB, anything less will really slow down the build.
+- Memory Size: at least 3000MB, anything less and the build might not complete.
![](gitian-building/create_vm_hard_disk.png)
@@ -95,14 +95,14 @@ After creating the VM, we need to configure it.
- Click `Ok` twice to save.
-Get the [Debian 8.x net installer](http://cdimage.debian.org/debian-cd/8.5.0/amd64/iso-cd/debian-8.5.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)).
-This DVD image can be validated using a SHA256 hashing tool, for example on
+Get the [Debian 8.x net installer](http://cdimage.debian.org/mirror/cdimage/archive/8.5.0/amd64/iso-cd/debian-8.5.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)).
+This DVD image can be [validated](https://www.debian.org/CD/verify) using a SHA256 hashing tool, for example on
Unixy OSes by entering the following in a terminal:
echo "ad4e8c27c561ad8248d5ebc1d36eb172f884057bfeb2c22ead823f59fa8c3dff debian-8.5.0-amd64-netinst.iso" | sha256sum -c
# (must return OK)
-Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded iso.
+Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded ISO.
![](gitian-building/select_startup_disk.png)
@@ -336,8 +336,10 @@ There will be a lot of warnings printed during the build of the image. These can
Getting and building the inputs
--------------------------------
-Follow the instructions in [doc/release-process.md](release-process.md#fetch-and-build-inputs-first-time-or-when-dependency-versions-change)
-in the bitcoin repository under 'Fetch and build inputs' to install sources which require
+At this point you have two options, you can either use the automated script (found in [contrib/gitian-build.sh](/contrib/gitian-build.sh)) or you could manually do everything by following this guide. If you're using the automated script, then run it with the "--setup" command. Afterwards, run it with the "--build" command (example: "contrib/gitian-build.sh -b signer 0.13.0"). Otherwise ignore this.
+
+Follow the instructions in [doc/release-process.md](release-process.md#fetch-and-create-inputs-first-time-or-when-dependency-versions-change)
+in the bitcoin repository under 'Fetch and create inputs' to install sources which require
manual intervention. Also optionally follow the next step: 'Seed the Gitian sources cache
and offline git repositories' which will fetch the remaining files required for building
offline.
diff --git a/doc/gitian-building/create_vm_memsize.png b/doc/gitian-building/create_vm_memsize.png
index 5abfee5337..6f42cda73f 100644
--- a/doc/gitian-building/create_vm_memsize.png
+++ b/doc/gitian-building/create_vm_memsize.png
Binary files differ
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
new file mode 100644
index 0000000000..08ff4d6ac1
--- /dev/null
+++ b/doc/man/Makefile.am
@@ -0,0 +1,13 @@
+dist_man1_MANS=
+
+if BUILD_BITCOIND
+ dist_man1_MANS+=bitcoind.1
+endif
+
+if ENABLE_QT
+ dist_man1_MANS+=bitcoin-qt.1
+endif
+
+if BUILD_BITCOIN_UTILS
+ dist_man1_MANS+=bitcoin-cli.1 bitcoin-tx.1
+endif
diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1
new file mode 100644
index 0000000000..0493241b1e
--- /dev/null
+++ b/doc/man/bitcoin-cli.1
@@ -0,0 +1,86 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
+.TH BITCOIN-CLI "1" "February 2017" "bitcoin-cli v0.14.99.0" "User Commands"
+.SH NAME
+bitcoin-cli \- manual page for bitcoin-cli v0.14.99.0
+.SH DESCRIPTION
+Bitcoin Core RPC client version v0.14.99.0
+.SS "Usage:"
+.TP
+bitcoin\-cli [options] <command> [params]
+Send command to Bitcoin Core
+.IP
+bitcoin\-cli [options] \fB\-named\fR <command> [name=value] ... Send command to Bitcoin Core (with named arguments)
+bitcoin\-cli [options] help List commands
+bitcoin\-cli [options] help <command> Get help for a command
+.SH OPTIONS
+.HP
+\-?
+.IP
+This help message
+.HP
+\fB\-conf=\fR<file>
+.IP
+Specify configuration file (default: bitcoin.conf)
+.HP
+\fB\-datadir=\fR<dir>
+.IP
+Specify data directory
+.PP
+Chain selection options:
+.HP
+\fB\-testnet\fR
+.IP
+Use the test chain
+.HP
+\fB\-regtest\fR
+.IP
+Enter regression test mode, which uses a special chain in which blocks
+can be solved instantly. This is intended for regression testing
+tools and app development.
+.HP
+\fB\-named\fR
+.IP
+Pass named instead of positional arguments (default: false)
+.HP
+\fB\-rpcconnect=\fR<ip>
+.IP
+Send commands to node running on <ip> (default: 127.0.0.1)
+.HP
+\fB\-rpcport=\fR<port>
+.IP
+Connect to JSON\-RPC on <port> (default: 8332 or testnet: 18332)
+.HP
+\fB\-rpcwait\fR
+.IP
+Wait for RPC server to start
+.HP
+\fB\-rpcuser=\fR<user>
+.IP
+Username for JSON\-RPC connections
+.HP
+\fB\-rpcpassword=\fR<pw>
+.IP
+Password for JSON\-RPC connections
+.HP
+\fB\-rpcclienttimeout=\fR<n>
+.IP
+Timeout during HTTP requests (default: 900)
+.HP
+\fB\-stdin\fR
+.IP
+Read extra arguments from standard input, one per line until EOF/Ctrl\-D
+(recommended for sensitive information such as passphrases)
+.SH COPYRIGHT
+Copyright (C) 2009-2017 The Bitcoin Core developers
+
+Please contribute if you find Bitcoin Core useful. Visit
+<https://bitcoincore.org> for further information about the software.
+The source code is available from <https://github.com/bitcoin/bitcoin>.
+
+This is experimental software.
+Distributed under the MIT software license, see the accompanying file COPYING
+or <https://opensource.org/licenses/MIT>
+
+This product includes software developed by the OpenSSL Project for use in the
+OpenSSL Toolkit <https://www.openssl.org> and cryptographic software written by
+Eric Young and UPnP software written by Thomas Bernard.
diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1
new file mode 100644
index 0000000000..ce252612e5
--- /dev/null
+++ b/doc/man/bitcoin-qt.1
@@ -0,0 +1,546 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
+.TH BITCOIN-QT "1" "February 2017" "bitcoin-qt v0.14.99.0" "User Commands"
+.SH NAME
+bitcoin-qt \- manual page for bitcoin-qt v0.14.99.0
+.SH DESCRIPTION
+Bitcoin Core version v0.14.99.0 (64\-bit)
+Usage:
+.IP
+bitcoin\-qt [command\-line options]
+.SH OPTIONS
+.HP
+\-?
+.IP
+Print this help message and exit
+.HP
+\fB\-version\fR
+.IP
+Print version and exit
+.HP
+\fB\-alertnotify=\fR<cmd>
+.IP
+Execute command when a relevant alert is received or we see a really
+long fork (%s in cmd is replaced by message)
+.HP
+\fB\-blocknotify=\fR<cmd>
+.IP
+Execute command when the best block changes (%s in cmd is replaced by
+block hash)
+.HP
+\fB\-assumevalid=\fR<hex>
+.IP
+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:
+00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90,
+testnet:
+00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc)
+.HP
+\fB\-conf=\fR<file>
+.IP
+Specify configuration file (default: bitcoin.conf)
+.HP
+\fB\-datadir=\fR<dir>
+.IP
+Specify data directory
+.HP
+\fB\-dbcache=\fR<n>
+.IP
+Set database cache size in megabytes (4 to 16384, default: 300)
+.HP
+\fB\-loadblock=\fR<file>
+.IP
+Imports blocks from external blk000??.dat file on startup
+.HP
+\fB\-maxorphantx=\fR<n>
+.IP
+Keep at most <n> unconnectable transactions in memory (default: 100)
+.HP
+\fB\-maxmempool=\fR<n>
+.IP
+Keep the transaction memory pool below <n> megabytes (default: 300)
+.HP
+\fB\-mempoolexpiry=\fR<n>
+.IP
+Do not keep transactions in the mempool longer than <n> hours (default:
+336)
+.HP
+\fB\-blockreconstructionextratxn=\fR<n>
+.IP
+Extra transactions to keep in memory for compact block reconstructions
+(default: 100)
+.HP
+\fB\-par=\fR<n>
+.IP
+Set the number of script verification threads (\fB\-2\fR to 16, 0 = auto, <0 =
+leave that many cores free, default: 0)
+.HP
+\fB\-pid=\fR<file>
+.IP
+Specify pid file (default: bitcoind.pid)
+.HP
+\fB\-prune=\fR<n>
+.IP
+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 \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting this
+setting requires re\-downloading the entire blockchain. (default:
+0 = disable pruning blocks, 1 = allow manual pruning via RPC,
+>550 = automatically prune block files to stay under the
+specified target size in MiB)
+.HP
+\fB\-reindex\-chainstate\fR
+.IP
+Rebuild chain state from the currently indexed blocks
+.HP
+\fB\-reindex\fR
+.IP
+Rebuild chain state and block index from the blk*.dat files on disk
+.HP
+\fB\-sysperms\fR
+.IP
+Create new files with system default permissions, instead of umask 077
+(only effective with disabled wallet functionality)
+.HP
+\fB\-txindex\fR
+.IP
+Maintain a full transaction index, used by the getrawtransaction rpc
+call (default: 0)
+.PP
+Connection options:
+.HP
+\fB\-addnode=\fR<ip>
+.IP
+Add a node to connect to and attempt to keep the connection open
+.HP
+\fB\-banscore=\fR<n>
+.IP
+Threshold for disconnecting misbehaving peers (default: 100)
+.HP
+\fB\-bantime=\fR<n>
+.IP
+Number of seconds to keep misbehaving peers from reconnecting (default:
+86400)
+.HP
+\fB\-bind=\fR<addr>
+.IP
+Bind to given address and always listen on it. Use [host]:port notation
+for IPv6
+.HP
+\fB\-connect=\fR<ip>
+.IP
+Connect only to the specified node(s); \fB\-noconnect\fR or \fB\-connect\fR=\fI\,0\/\fR alone to
+disable automatic connections
+.HP
+\fB\-discover\fR
+.IP
+Discover own IP addresses (default: 1 when listening and no \fB\-externalip\fR
+or \fB\-proxy\fR)
+.HP
+\fB\-dns\fR
+.IP
+Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (default: 1)
+.HP
+\fB\-dnsseed\fR
+.IP
+Query for peer addresses via DNS lookup, if low on addresses (default: 1
+unless \fB\-connect\fR/\-noconnect)
+.HP
+\fB\-externalip=\fR<ip>
+.IP
+Specify your own public address
+.HP
+\fB\-forcednsseed\fR
+.IP
+Always query for peer addresses via DNS lookup (default: 0)
+.HP
+\fB\-listen\fR
+.IP
+Accept connections from outside (default: 1 if no \fB\-proxy\fR or
+\fB\-connect\fR/\-noconnect)
+.HP
+\fB\-listenonion\fR
+.IP
+Automatically create Tor hidden service (default: 1)
+.HP
+\fB\-maxconnections=\fR<n>
+.IP
+Maintain at most <n> connections to peers (default: 125)
+.HP
+\fB\-maxreceivebuffer=\fR<n>
+.IP
+Maximum per\-connection receive buffer, <n>*1000 bytes (default: 5000)
+.HP
+\fB\-maxsendbuffer=\fR<n>
+.IP
+Maximum per\-connection send buffer, <n>*1000 bytes (default: 1000)
+.HP
+\fB\-maxtimeadjustment\fR
+.IP
+Maximum allowed median peer time offset adjustment. Local perspective of
+time may be influenced by peers forward or backward by this
+amount. (default: 4200 seconds)
+.HP
+\fB\-onion=\fR<ip:port>
+.IP
+Use separate SOCKS5 proxy to reach peers via Tor hidden services
+(default: \fB\-proxy\fR)
+.HP
+\fB\-onlynet=\fR<net>
+.IP
+Only connect to nodes in network <net> (ipv4, ipv6 or onion)
+.HP
+\fB\-permitbaremultisig\fR
+.IP
+Relay non\-P2SH multisig (default: 1)
+.HP
+\fB\-peerbloomfilters\fR
+.IP
+Support filtering of blocks and transaction with bloom filters (default:
+1)
+.HP
+\fB\-port=\fR<port>
+.IP
+Listen for connections on <port> (default: 8333 or testnet: 18333)
+.HP
+\fB\-proxy=\fR<ip:port>
+.IP
+Connect through SOCKS5 proxy
+.HP
+\fB\-proxyrandomize\fR
+.IP
+Randomize credentials for every proxy connection. This enables Tor
+stream isolation (default: 1)
+.HP
+\fB\-rpcserialversion\fR
+.IP
+Sets the serialization of raw transaction or block hex returned in
+non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1)
+.HP
+\fB\-seednode=\fR<ip>
+.IP
+Connect to a node to retrieve peer addresses, and disconnect
+.HP
+\fB\-timeout=\fR<n>
+.IP
+Specify connection timeout in milliseconds (minimum: 1, default: 5000)
+.HP
+\fB\-torcontrol=\fR<ip>:<port>
+.IP
+Tor control port to use if onion listening enabled (default:
+127.0.0.1:9051)
+.HP
+\fB\-torpassword=\fR<pass>
+.IP
+Tor control port password (default: empty)
+.HP
+\fB\-upnp\fR
+.IP
+Use UPnP to map the listening port (default: 0)
+.HP
+\fB\-whitebind=\fR<addr>
+.IP
+Bind to given address and whitelist peers connecting to it. Use
+[host]:port notation for IPv6
+.HP
+\fB\-whitelist=\fR<IP address or network>
+.IP
+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
+.HP
+\fB\-whitelistrelay\fR
+.IP
+Accept relayed transactions received from whitelisted peers even when
+not relaying transactions (default: 1)
+.HP
+\fB\-whitelistforcerelay\fR
+.IP
+Force relay of transactions from whitelisted peers even if they violate
+local relay policy (default: 1)
+.HP
+\fB\-maxuploadtarget=\fR<n>
+.IP
+Tries to keep outbound traffic under the given target (in MiB per 24h),
+0 = no limit (default: 0)
+.PP
+Wallet options:
+.HP
+\fB\-disablewallet\fR
+.IP
+Do not load the wallet and disable wallet RPC calls
+.HP
+\fB\-keypool=\fR<n>
+.IP
+Set key pool size to <n> (default: 100)
+.HP
+\fB\-fallbackfee=\fR<amt>
+.IP
+A fee rate (in BTC/kB) that will be used when fee estimation has
+insufficient data (default: 0.0002)
+.HP
+\fB\-mintxfee=\fR<amt>
+.IP
+Fees (in BTC/kB) smaller than this are considered zero fee for
+transaction creation (default: 0.00001)
+.HP
+\fB\-paytxfee=\fR<amt>
+.IP
+Fee (in BTC/kB) to add to transactions you send (default: 0.00)
+.HP
+\fB\-rescan\fR
+.IP
+Rescan the block chain for missing wallet transactions on startup
+.HP
+\fB\-salvagewallet\fR
+.IP
+Attempt to recover private keys from a corrupt wallet on startup
+.HP
+\fB\-spendzeroconfchange\fR
+.IP
+Spend unconfirmed change when sending transactions (default: 1)
+.HP
+\fB\-txconfirmtarget=\fR<n>
+.IP
+If paytxfee is not set, include enough fee so transactions begin
+confirmation on average within n blocks (default: 6)
+.HP
+\fB\-usehd\fR
+.IP
+Use hierarchical deterministic key generation (HD) after BIP32. Only has
+effect during wallet creation/first start (default: 1)
+.HP
+\fB\-walletrbf\fR
+.IP
+Send transactions with full\-RBF opt\-in enabled (default: 0)
+.HP
+\fB\-upgradewallet\fR
+.IP
+Upgrade wallet to latest format on startup
+.HP
+\fB\-wallet=\fR<file>
+.IP
+Specify wallet file (within data directory) (default: wallet.dat)
+.HP
+\fB\-walletbroadcast\fR
+.IP
+Make the wallet broadcast transactions (default: 1)
+.HP
+\fB\-walletnotify=\fR<cmd>
+.IP
+Execute command when a wallet transaction changes (%s in cmd is replaced
+by TxID)
+.HP
+\fB\-zapwallettxes=\fR<mode>
+.IP
+Delete all wallet transactions and only recover those parts of the
+blockchain through \fB\-rescan\fR on startup (1 = keep tx meta data e.g.
+account owner and payment request information, 2 = drop tx meta
+data)
+.PP
+ZeroMQ notification options:
+.HP
+\fB\-zmqpubhashblock=\fR<address>
+.IP
+Enable publish hash block in <address>
+.HP
+\fB\-zmqpubhashtx=\fR<address>
+.IP
+Enable publish hash transaction in <address>
+.HP
+\fB\-zmqpubrawblock=\fR<address>
+.IP
+Enable publish raw block in <address>
+.HP
+\fB\-zmqpubrawtx=\fR<address>
+.IP
+Enable publish raw transaction in <address>
+.PP
+Debugging/Testing options:
+.HP
+\fB\-uacomment=\fR<cmt>
+.IP
+Append comment to the user agent string
+.HP
+\fB\-debug=\fR<category>
+.IP
+Output debugging information (default: 0, supplying <category> is
+optional). If <category> is not supplied or if <category> = 1,
+output all debugging information.<category> can be: addrman,
+alert, bench, cmpctblock, coindb, db, http, libevent, lock,
+mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc,
+selectcoins, tor, zmq, qt.
+.HP
+\fB\-help\-debug\fR
+.IP
+Show all debugging options (usage: \fB\-\-help\fR \fB\-help\-debug\fR)
+.HP
+\fB\-logips\fR
+.IP
+Include IP addresses in debug output (default: 0)
+.HP
+\fB\-logtimestamps\fR
+.IP
+Prepend debug output with timestamp (default: 1)
+.HP
+\fB\-minrelaytxfee=\fR<amt>
+.IP
+Fees (in BTC/kB) smaller than this are considered zero fee for relaying,
+mining and transaction creation (default: 0.00001)
+.HP
+\fB\-maxtxfee=\fR<amt>
+.IP
+Maximum total fees (in BTC) to use in a single wallet transaction or raw
+transaction; setting this too low may abort large transactions
+(default: 0.10)
+.HP
+\fB\-printtoconsole\fR
+.IP
+Send trace/debug info to console instead of debug.log file
+.HP
+\fB\-shrinkdebugfile\fR
+.IP
+Shrink debug.log file on client startup (default: 1 when no \fB\-debug\fR)
+.PP
+Chain selection options:
+.HP
+\fB\-testnet\fR
+.IP
+Use the test chain
+.PP
+Node relay options:
+.HP
+\fB\-bytespersigop\fR
+.IP
+Equivalent bytes per sigop in transactions for relay and mining
+(default: 20)
+.HP
+\fB\-datacarrier\fR
+.IP
+Relay and mine data carrier transactions (default: 1)
+.HP
+\fB\-datacarriersize\fR
+.IP
+Maximum size of data in data carrier transactions we relay and mine
+(default: 83)
+.HP
+\fB\-mempoolreplacement\fR
+.IP
+Enable transaction replacement in the memory pool (default: 1)
+.PP
+Block creation options:
+.HP
+\fB\-blockmaxweight=\fR<n>
+.IP
+Set maximum BIP141 block weight (default: 3000000)
+.HP
+\fB\-blockmaxsize=\fR<n>
+.IP
+Set maximum block size in bytes (default: 750000)
+.HP
+\fB\-blockprioritysize=\fR<n>
+.IP
+Set maximum size of high\-priority/low\-fee transactions in bytes
+(default: 0)
+.HP
+\fB\-blockmintxfee=\fR<amt>
+.IP
+Set lowest fee rate (in BTC/kB) for transactions to be included in block
+creation. (default: 0.00001)
+.PP
+RPC server options:
+.HP
+\fB\-server\fR
+.IP
+Accept command line and JSON\-RPC commands
+.HP
+\fB\-rest\fR
+.IP
+Accept public REST requests (default: 0)
+.HP
+\fB\-rpcbind=\fR<addr>
+.IP
+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)
+.HP
+\fB\-rpccookiefile=\fR<loc>
+.IP
+Location of the auth cookie (default: data dir)
+.HP
+\fB\-rpcuser=\fR<user>
+.IP
+Username for JSON\-RPC connections
+.HP
+\fB\-rpcpassword=\fR<pw>
+.IP
+Password for JSON\-RPC connections
+.HP
+\fB\-rpcauth=\fR<userpw>
+.IP
+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
+.HP
+\fB\-rpcport=\fR<port>
+.IP
+Listen for JSON\-RPC connections on <port> (default: 8332 or testnet:
+18332)
+.HP
+\fB\-rpcallowip=\fR<ip>
+.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
+.HP
+\fB\-rpcthreads=\fR<n>
+.IP
+Set the number of threads to service RPC calls (default: 4)
+.PP
+UI Options:
+.HP
+\fB\-choosedatadir\fR
+.IP
+Choose data directory on startup (default: 0)
+.HP
+\fB\-lang=\fR<lang>
+.IP
+Set language, for example "de_DE" (default: system locale)
+.HP
+\fB\-min\fR
+.IP
+Start minimized
+.HP
+\fB\-rootcertificates=\fR<file>
+.IP
+Set SSL root certificates for payment request (default: \fB\-system\-\fR)
+.HP
+\fB\-splash\fR
+.IP
+Show splash screen on startup (default: 1)
+.HP
+\fB\-resetguisettings\fR
+.IP
+Reset all settings changed in the GUI
+.SH COPYRIGHT
+Copyright (C) 2009-2017 The Bitcoin Core developers
+
+Please contribute if you find Bitcoin Core useful. Visit
+<https://bitcoincore.org> for further information about the software.
+The source code is available from <https://github.com/bitcoin/bitcoin>.
+
+This is experimental software.
+Distributed under the MIT software license, see the accompanying file COPYING
+or <https://opensource.org/licenses/MIT>
+
+This product includes software developed by the OpenSSL Project for use in the
+OpenSSL Toolkit <https://www.openssl.org> and cryptographic software written by
+Eric Young and UPnP software written by Thomas Bernard.
diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1
new file mode 100644
index 0000000000..98adf2f5b1
--- /dev/null
+++ b/doc/man/bitcoin-tx.1
@@ -0,0 +1,122 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
+.TH BITCOIN-TX "1" "February 2017" "bitcoin-tx v0.14.99.0" "User Commands"
+.SH NAME
+bitcoin-tx \- manual page for bitcoin-tx v0.14.99.0
+.SH DESCRIPTION
+Bitcoin Core bitcoin\-tx utility version v0.14.99.0
+.SS "Usage:"
+.TP
+bitcoin\-tx [options] <hex\-tx> [commands]
+Update hex\-encoded bitcoin transaction
+.TP
+bitcoin\-tx [options] \fB\-create\fR [commands]
+Create hex\-encoded bitcoin transaction
+.SH OPTIONS
+.HP
+\-?
+.IP
+This help message
+.HP
+\fB\-create\fR
+.IP
+Create new, empty TX.
+.HP
+\fB\-json\fR
+.IP
+Select JSON output
+.HP
+\fB\-txid\fR
+.IP
+Output only the hex\-encoded transaction id of the resultant transaction.
+.PP
+Chain selection options:
+.HP
+\fB\-testnet\fR
+.IP
+Use the test chain
+.HP
+\fB\-regtest\fR
+.IP
+Enter regression test mode, which uses a special chain in which blocks
+can be solved instantly. This is intended for regression testing
+tools and app development.
+.PP
+Commands:
+.IP
+delin=N
+.IP
+Delete input N from TX
+.IP
+delout=N
+.IP
+Delete output N from TX
+.IP
+in=TXID:VOUT(:SEQUENCE_NUMBER)
+.IP
+Add input to TX
+.IP
+locktime=N
+.IP
+Set TX lock time to N
+.IP
+nversion=N
+.IP
+Set TX version to N
+.IP
+outaddr=VALUE:ADDRESS
+.IP
+Add address\-based output to TX
+.IP
+outpubkey=VALUE:PUBKEY[:FLAGS]
+.IP
+Add pay\-to\-pubkey output to TX. Optionally add the "W" flag to produce a
+pay\-to\-witness\-pubkey\-hash output. Optionally add the "S" flag to
+wrap the output in a pay\-to\-script\-hash.
+.IP
+outdata=[VALUE:]DATA
+.IP
+Add data\-based output to TX
+.IP
+outscript=VALUE:SCRIPT[:FLAGS]
+.IP
+Add raw script output to TX. Optionally add the "W" flag to produce a
+pay\-to\-witness\-script\-hash output. Optionally add the "S" flag to
+wrap the output in a pay\-to\-script\-hash.
+.IP
+outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
+.IP
+Add Pay To n\-of\-m Multi\-sig output to TX. n = REQUIRED, m = PUBKEYS.
+Optionally add the "W" flag to produce a
+pay\-to\-witness\-script\-hash output. Optionally add the "S" flag to
+wrap the output in a pay\-to\-script\-hash.
+.IP
+sign=SIGHASH\-FLAGS
+.IP
+Add zero or more signatures to transaction. This command requires JSON
+registers:prevtxs=JSON object, privatekeys=JSON object. See
+signrawtransaction docs for format of sighash flags, JSON
+objects.
+.PP
+Register Commands:
+.IP
+load=NAME:FILENAME
+.IP
+Load JSON file FILENAME into register NAME
+.IP
+set=NAME:JSON\-STRING
+.IP
+Set register NAME to given JSON\-STRING
+.SH COPYRIGHT
+Copyright (C) 2009-2017 The Bitcoin Core developers
+
+Please contribute if you find Bitcoin Core useful. Visit
+<https://bitcoincore.org> for further information about the software.
+The source code is available from <https://github.com/bitcoin/bitcoin>.
+
+This is experimental software.
+Distributed under the MIT software license, see the accompanying file COPYING
+or <https://opensource.org/licenses/MIT>
+
+This product includes software developed by the OpenSSL Project for use in the
+OpenSSL Toolkit <https://www.openssl.org> and cryptographic software written by
+Eric Young and UPnP software written by Thomas Bernard.
diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1
new file mode 100644
index 0000000000..fb066e0c6f
--- /dev/null
+++ b/doc/man/bitcoind.1
@@ -0,0 +1,525 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
+.TH BITCOIND "1" "February 2017" "bitcoind v0.14.99.0" "User Commands"
+.SH NAME
+bitcoind \- manual page for bitcoind v0.14.99.0
+.SH DESCRIPTION
+Bitcoin Core Daemon version v0.14.99.0
+.SS "Usage:"
+.TP
+bitcoind [options]
+Start Bitcoin Core Daemon
+.SH OPTIONS
+.HP
+\-?
+.IP
+Print this help message and exit
+.HP
+\fB\-version\fR
+.IP
+Print version and exit
+.HP
+\fB\-alertnotify=\fR<cmd>
+.IP
+Execute command when a relevant alert is received or we see a really
+long fork (%s in cmd is replaced by message)
+.HP
+\fB\-blocknotify=\fR<cmd>
+.IP
+Execute command when the best block changes (%s in cmd is replaced by
+block hash)
+.HP
+\fB\-assumevalid=\fR<hex>
+.IP
+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:
+00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90,
+testnet:
+00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc)
+.HP
+\fB\-conf=\fR<file>
+.IP
+Specify configuration file (default: bitcoin.conf)
+.HP
+\fB\-daemon\fR
+.IP
+Run in the background as a daemon and accept commands
+.HP
+\fB\-datadir=\fR<dir>
+.IP
+Specify data directory
+.HP
+\fB\-dbcache=\fR<n>
+.IP
+Set database cache size in megabytes (4 to 16384, default: 300)
+.HP
+\fB\-loadblock=\fR<file>
+.IP
+Imports blocks from external blk000??.dat file on startup
+.HP
+\fB\-maxorphantx=\fR<n>
+.IP
+Keep at most <n> unconnectable transactions in memory (default: 100)
+.HP
+\fB\-maxmempool=\fR<n>
+.IP
+Keep the transaction memory pool below <n> megabytes (default: 300)
+.HP
+\fB\-mempoolexpiry=\fR<n>
+.IP
+Do not keep transactions in the mempool longer than <n> hours (default:
+336)
+.HP
+\fB\-blockreconstructionextratxn=\fR<n>
+.IP
+Extra transactions to keep in memory for compact block reconstructions
+(default: 100)
+.HP
+\fB\-par=\fR<n>
+.IP
+Set the number of script verification threads (\fB\-2\fR to 16, 0 = auto, <0 =
+leave that many cores free, default: 0)
+.HP
+\fB\-pid=\fR<file>
+.IP
+Specify pid file (default: bitcoind.pid)
+.HP
+\fB\-prune=\fR<n>
+.IP
+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 \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting this
+setting requires re\-downloading the entire blockchain. (default:
+0 = disable pruning blocks, 1 = allow manual pruning via RPC,
+>550 = automatically prune block files to stay under the
+specified target size in MiB)
+.HP
+\fB\-reindex\-chainstate\fR
+.IP
+Rebuild chain state from the currently indexed blocks
+.HP
+\fB\-reindex\fR
+.IP
+Rebuild chain state and block index from the blk*.dat files on disk
+.HP
+\fB\-sysperms\fR
+.IP
+Create new files with system default permissions, instead of umask 077
+(only effective with disabled wallet functionality)
+.HP
+\fB\-txindex\fR
+.IP
+Maintain a full transaction index, used by the getrawtransaction rpc
+call (default: 0)
+.PP
+Connection options:
+.HP
+\fB\-addnode=\fR<ip>
+.IP
+Add a node to connect to and attempt to keep the connection open
+.HP
+\fB\-banscore=\fR<n>
+.IP
+Threshold for disconnecting misbehaving peers (default: 100)
+.HP
+\fB\-bantime=\fR<n>
+.IP
+Number of seconds to keep misbehaving peers from reconnecting (default:
+86400)
+.HP
+\fB\-bind=\fR<addr>
+.IP
+Bind to given address and always listen on it. Use [host]:port notation
+for IPv6
+.HP
+\fB\-connect=\fR<ip>
+.IP
+Connect only to the specified node(s); \fB\-noconnect\fR or \fB\-connect\fR=\fI\,0\/\fR alone to
+disable automatic connections
+.HP
+\fB\-discover\fR
+.IP
+Discover own IP addresses (default: 1 when listening and no \fB\-externalip\fR
+or \fB\-proxy\fR)
+.HP
+\fB\-dns\fR
+.IP
+Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (default: 1)
+.HP
+\fB\-dnsseed\fR
+.IP
+Query for peer addresses via DNS lookup, if low on addresses (default: 1
+unless \fB\-connect\fR/\-noconnect)
+.HP
+\fB\-externalip=\fR<ip>
+.IP
+Specify your own public address
+.HP
+\fB\-forcednsseed\fR
+.IP
+Always query for peer addresses via DNS lookup (default: 0)
+.HP
+\fB\-listen\fR
+.IP
+Accept connections from outside (default: 1 if no \fB\-proxy\fR or
+\fB\-connect\fR/\-noconnect)
+.HP
+\fB\-listenonion\fR
+.IP
+Automatically create Tor hidden service (default: 1)
+.HP
+\fB\-maxconnections=\fR<n>
+.IP
+Maintain at most <n> connections to peers (default: 125)
+.HP
+\fB\-maxreceivebuffer=\fR<n>
+.IP
+Maximum per\-connection receive buffer, <n>*1000 bytes (default: 5000)
+.HP
+\fB\-maxsendbuffer=\fR<n>
+.IP
+Maximum per\-connection send buffer, <n>*1000 bytes (default: 1000)
+.HP
+\fB\-maxtimeadjustment\fR
+.IP
+Maximum allowed median peer time offset adjustment. Local perspective of
+time may be influenced by peers forward or backward by this
+amount. (default: 4200 seconds)
+.HP
+\fB\-onion=\fR<ip:port>
+.IP
+Use separate SOCKS5 proxy to reach peers via Tor hidden services
+(default: \fB\-proxy\fR)
+.HP
+\fB\-onlynet=\fR<net>
+.IP
+Only connect to nodes in network <net> (ipv4, ipv6 or onion)
+.HP
+\fB\-permitbaremultisig\fR
+.IP
+Relay non\-P2SH multisig (default: 1)
+.HP
+\fB\-peerbloomfilters\fR
+.IP
+Support filtering of blocks and transaction with bloom filters (default:
+1)
+.HP
+\fB\-port=\fR<port>
+.IP
+Listen for connections on <port> (default: 8333 or testnet: 18333)
+.HP
+\fB\-proxy=\fR<ip:port>
+.IP
+Connect through SOCKS5 proxy
+.HP
+\fB\-proxyrandomize\fR
+.IP
+Randomize credentials for every proxy connection. This enables Tor
+stream isolation (default: 1)
+.HP
+\fB\-rpcserialversion\fR
+.IP
+Sets the serialization of raw transaction or block hex returned in
+non\-verbose mode, non\-segwit(0) or segwit(1) (default: 1)
+.HP
+\fB\-seednode=\fR<ip>
+.IP
+Connect to a node to retrieve peer addresses, and disconnect
+.HP
+\fB\-timeout=\fR<n>
+.IP
+Specify connection timeout in milliseconds (minimum: 1, default: 5000)
+.HP
+\fB\-torcontrol=\fR<ip>:<port>
+.IP
+Tor control port to use if onion listening enabled (default:
+127.0.0.1:9051)
+.HP
+\fB\-torpassword=\fR<pass>
+.IP
+Tor control port password (default: empty)
+.HP
+\fB\-upnp\fR
+.IP
+Use UPnP to map the listening port (default: 0)
+.HP
+\fB\-whitebind=\fR<addr>
+.IP
+Bind to given address and whitelist peers connecting to it. Use
+[host]:port notation for IPv6
+.HP
+\fB\-whitelist=\fR<IP address or network>
+.IP
+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
+.HP
+\fB\-whitelistrelay\fR
+.IP
+Accept relayed transactions received from whitelisted peers even when
+not relaying transactions (default: 1)
+.HP
+\fB\-whitelistforcerelay\fR
+.IP
+Force relay of transactions from whitelisted peers even if they violate
+local relay policy (default: 1)
+.HP
+\fB\-maxuploadtarget=\fR<n>
+.IP
+Tries to keep outbound traffic under the given target (in MiB per 24h),
+0 = no limit (default: 0)
+.PP
+Wallet options:
+.HP
+\fB\-disablewallet\fR
+.IP
+Do not load the wallet and disable wallet RPC calls
+.HP
+\fB\-keypool=\fR<n>
+.IP
+Set key pool size to <n> (default: 100)
+.HP
+\fB\-fallbackfee=\fR<amt>
+.IP
+A fee rate (in BTC/kB) that will be used when fee estimation has
+insufficient data (default: 0.0002)
+.HP
+\fB\-mintxfee=\fR<amt>
+.IP
+Fees (in BTC/kB) smaller than this are considered zero fee for
+transaction creation (default: 0.00001)
+.HP
+\fB\-paytxfee=\fR<amt>
+.IP
+Fee (in BTC/kB) to add to transactions you send (default: 0.00)
+.HP
+\fB\-rescan\fR
+.IP
+Rescan the block chain for missing wallet transactions on startup
+.HP
+\fB\-salvagewallet\fR
+.IP
+Attempt to recover private keys from a corrupt wallet on startup
+.HP
+\fB\-spendzeroconfchange\fR
+.IP
+Spend unconfirmed change when sending transactions (default: 1)
+.HP
+\fB\-txconfirmtarget=\fR<n>
+.IP
+If paytxfee is not set, include enough fee so transactions begin
+confirmation on average within n blocks (default: 6)
+.HP
+\fB\-usehd\fR
+.IP
+Use hierarchical deterministic key generation (HD) after BIP32. Only has
+effect during wallet creation/first start (default: 1)
+.HP
+\fB\-walletrbf\fR
+.IP
+Send transactions with full\-RBF opt\-in enabled (default: 0)
+.HP
+\fB\-upgradewallet\fR
+.IP
+Upgrade wallet to latest format on startup
+.HP
+\fB\-wallet=\fR<file>
+.IP
+Specify wallet file (within data directory) (default: wallet.dat)
+.HP
+\fB\-walletbroadcast\fR
+.IP
+Make the wallet broadcast transactions (default: 1)
+.HP
+\fB\-walletnotify=\fR<cmd>
+.IP
+Execute command when a wallet transaction changes (%s in cmd is replaced
+by TxID)
+.HP
+\fB\-zapwallettxes=\fR<mode>
+.IP
+Delete all wallet transactions and only recover those parts of the
+blockchain through \fB\-rescan\fR on startup (1 = keep tx meta data e.g.
+account owner and payment request information, 2 = drop tx meta
+data)
+.PP
+ZeroMQ notification options:
+.HP
+\fB\-zmqpubhashblock=\fR<address>
+.IP
+Enable publish hash block in <address>
+.HP
+\fB\-zmqpubhashtx=\fR<address>
+.IP
+Enable publish hash transaction in <address>
+.HP
+\fB\-zmqpubrawblock=\fR<address>
+.IP
+Enable publish raw block in <address>
+.HP
+\fB\-zmqpubrawtx=\fR<address>
+.IP
+Enable publish raw transaction in <address>
+.PP
+Debugging/Testing options:
+.HP
+\fB\-uacomment=\fR<cmt>
+.IP
+Append comment to the user agent string
+.HP
+\fB\-debug=\fR<category>
+.IP
+Output debugging information (default: 0, supplying <category> is
+optional). If <category> is not supplied or if <category> = 1,
+output all debugging information.<category> can be: addrman,
+alert, bench, cmpctblock, coindb, db, http, libevent, lock,
+mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc,
+selectcoins, tor, zmq.
+.HP
+\fB\-help\-debug\fR
+.IP
+Show all debugging options (usage: \fB\-\-help\fR \fB\-help\-debug\fR)
+.HP
+\fB\-logips\fR
+.IP
+Include IP addresses in debug output (default: 0)
+.HP
+\fB\-logtimestamps\fR
+.IP
+Prepend debug output with timestamp (default: 1)
+.HP
+\fB\-minrelaytxfee=\fR<amt>
+.IP
+Fees (in BTC/kB) smaller than this are considered zero fee for relaying,
+mining and transaction creation (default: 0.00001)
+.HP
+\fB\-maxtxfee=\fR<amt>
+.IP
+Maximum total fees (in BTC) to use in a single wallet transaction or raw
+transaction; setting this too low may abort large transactions
+(default: 0.10)
+.HP
+\fB\-printtoconsole\fR
+.IP
+Send trace/debug info to console instead of debug.log file
+.HP
+\fB\-shrinkdebugfile\fR
+.IP
+Shrink debug.log file on client startup (default: 1 when no \fB\-debug\fR)
+.PP
+Chain selection options:
+.HP
+\fB\-testnet\fR
+.IP
+Use the test chain
+.PP
+Node relay options:
+.HP
+\fB\-bytespersigop\fR
+.IP
+Equivalent bytes per sigop in transactions for relay and mining
+(default: 20)
+.HP
+\fB\-datacarrier\fR
+.IP
+Relay and mine data carrier transactions (default: 1)
+.HP
+\fB\-datacarriersize\fR
+.IP
+Maximum size of data in data carrier transactions we relay and mine
+(default: 83)
+.HP
+\fB\-mempoolreplacement\fR
+.IP
+Enable transaction replacement in the memory pool (default: 1)
+.PP
+Block creation options:
+.HP
+\fB\-blockmaxweight=\fR<n>
+.IP
+Set maximum BIP141 block weight (default: 3000000)
+.HP
+\fB\-blockmaxsize=\fR<n>
+.IP
+Set maximum block size in bytes (default: 750000)
+.HP
+\fB\-blockprioritysize=\fR<n>
+.IP
+Set maximum size of high\-priority/low\-fee transactions in bytes
+(default: 0)
+.HP
+\fB\-blockmintxfee=\fR<amt>
+.IP
+Set lowest fee rate (in BTC/kB) for transactions to be included in block
+creation. (default: 0.00001)
+.PP
+RPC server options:
+.HP
+\fB\-server\fR
+.IP
+Accept command line and JSON\-RPC commands
+.HP
+\fB\-rest\fR
+.IP
+Accept public REST requests (default: 0)
+.HP
+\fB\-rpcbind=\fR<addr>
+.IP
+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)
+.HP
+\fB\-rpccookiefile=\fR<loc>
+.IP
+Location of the auth cookie (default: data dir)
+.HP
+\fB\-rpcuser=\fR<user>
+.IP
+Username for JSON\-RPC connections
+.HP
+\fB\-rpcpassword=\fR<pw>
+.IP
+Password for JSON\-RPC connections
+.HP
+\fB\-rpcauth=\fR<userpw>
+.IP
+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
+.HP
+\fB\-rpcport=\fR<port>
+.IP
+Listen for JSON\-RPC connections on <port> (default: 8332 or testnet:
+18332)
+.HP
+\fB\-rpcallowip=\fR<ip>
+.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
+.HP
+\fB\-rpcthreads=\fR<n>
+.IP
+Set the number of threads to service RPC calls (default: 4)
+.SH COPYRIGHT
+Copyright (C) 2009-2017 The Bitcoin Core developers
+
+Please contribute if you find Bitcoin Core useful. Visit
+<https://bitcoincore.org> for further information about the software.
+The source code is available from <https://github.com/bitcoin/bitcoin>.
+
+This is experimental software.
+Distributed under the MIT software license, see the accompanying file COPYING
+or <https://opensource.org/licenses/MIT>
+
+This product includes software developed by the OpenSSL Project for use in the
+OpenSSL Toolkit <https://www.openssl.org> and cryptographic software written by
+Eric Young and UPnP software written by Thomas Bernard.
diff --git a/doc/multiwallet-qt.md b/doc/multiwallet-qt.md
deleted file mode 100644
index 3caab81807..0000000000
--- a/doc/multiwallet-qt.md
+++ /dev/null
@@ -1,48 +0,0 @@
-Multiwallet Qt Development and Integration Strategy
-===================================================
-
-In order to support loading of multiple wallets in bitcoin-qt, a few changes in the UI architecture will be needed.
-Fortunately, only four of the files in the existing project are affected by this change.
-
-Two new classes have been implemented in two new .h/.cpp file pairs, with much of the functionality that was previously
-implemented in the BitcoinGUI class moved over to these new classes.
-
-The two existing files most affected, by far, are bitcoingui.h and bitcoingui.cpp, as the BitcoinGUI class will require
-some major retrofitting.
-
-Only requiring some minor changes is bitcoin.cpp.
-
-Finally, two new headers and source files will have to be added to bitcoin-qt.pro.
-
-Changes to class BitcoinGUI
----------------------------
-The principal change to the BitcoinGUI class concerns the QStackedWidget instance called centralWidget.
-This widget owns five page views: overviewPage, transactionsPage, addressBookPage, receiveCoinsPage, and sendCoinsPage.
-
-A new class called *WalletView* inheriting from QStackedWidget has been written to handle all renderings and updates of
-these page views. In addition to owning these five page views, a WalletView also has a pointer to a WalletModel instance.
-This allows the construction of multiple WalletView objects, each rendering a distinct wallet.
-
-A second class called *WalletFrame* inheriting from QFrame has been written as a container for embedding all wallet-related
-controls into BitcoinGUI. At present it contains the WalletView instances for the wallets and does little more than passing on messages
-from BitcoinGUI to the currently selected WalletView. It is a WalletFrame instance
-that takes the place of what used to be centralWidget in BitcoinGUI. The purpose of this class is to allow future
-refinements of the wallet controls with minimal need for further modifications to BitcoinGUI, thus greatly simplifying
-merges while reducing the risk of breaking top-level stuff.
-
-Changes to bitcoin.cpp
-----------------------
-bitcoin.cpp is the entry point into bitcoin-qt, and as such, will require some minor modifications to provide hooks for
-multiple wallet support. Most importantly will be the way it instantiates WalletModels and passes them to the
-singleton BitcoinGUI instance called window. Formerly, BitcoinGUI kept a pointer to a single instance of a WalletModel.
-The initial change required is very simple: rather than calling `window.setWalletModel(&walletModel);` we perform the
-following two steps:
-
- window.addWallet("~Default", &walletModel);
- window.setCurrentWallet("~Default");
-
-The string parameter is just an arbitrary name given to the default wallet. It's been prepended with a tilde to avoid name collisions in the future with additional wallets.
-
-The shutdown call `window.setWalletModel(0)` has also been removed. In its place is now:
-
-window.removeAllWallets();
diff --git a/doc/reduce-traffic.md b/doc/reduce-traffic.md
index 2d86588eb2..697099beab 100644
--- a/doc/reduce-traffic.md
+++ b/doc/reduce-traffic.md
@@ -19,8 +19,7 @@ This is *not* a hard limit; only a threshold to minimize the outbound
traffic. When the limit is about to be reached, the uploaded data is cut by no
longer serving historic blocks (blocks older than one week).
Keep in mind that new nodes require other nodes that are willing to serve
-historic blocks. **The recommended minimum is 144 blocks per day (max. 144MB
-per day)**
+historic blocks.
Whitelisted peers will never be disconnected, although their traffic counts for
calculating the target.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 3d2baaaaea..af792118d6 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -19,189 +19,73 @@ To receive security and update notifications, please subscribe to:
Compatibility
==============
-Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support),
-an OS initially released in 2001. This means that not even critical security
-updates will be released anymore. Without security updates, using a bitcoin
-wallet on a XP machine is irresponsible at least.
+Bitcoin Core is extensively tested on multiple operating systems using
+the Linux kernel, macOS 10.8+, and Windows Vista and later.
-In addition to that, with 0.12.x there have been varied reports of Bitcoin Core
-randomly crashing on Windows XP. It is [not clear](https://github.com/bitcoin/bitcoin/issues/7681#issuecomment-217439891)
-what the source of these crashes is, but it is likely that upstream
-libraries such as Qt are no longer being tested on XP.
+Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support).
+No attempt is made to prevent installing or running the software on Windows XP, you
+can still do so at your own risk but be aware that there are known instabilities.
+Please do not report issues about Windows XP to the issue tracker.
-We do not have time nor resources to provide support for an OS that is
-end-of-life. From 0.13.0 on, Windows XP is no longer supported. Users are
-suggested to upgrade to a newer verion of Windows, or install an alternative OS
-that is supported.
-
-No attempt is made to prevent installing or running the software on Windows XP,
-you can still do so at your own risk, but do not expect it to work: do not
-report issues about Windows XP to the issue tracker.
+Bitcoin Core should also work on most other Unix-like systems but is not
+frequently tested on them.
Notable changes
===============
-Database cache memory increased
---------------------------------
-
-As a result of growth of the UTXO set, performance with the prior default
-database cache of 100 MiB has suffered.
-For this reason the default was changed to 300 MiB in this release.
-
-For nodes on low-memory systems, the database cache can be changed back to
-100 MiB (or to another value) by either:
-
-- Adding `dbcache=100` in bitcoin.conf
-- Changing it in the GUI under `Options → Size of database cache`
-
-Note that the database cache setting has the most performance impact
-during initial sync of a node, and when catching up after downtime.
-
-bitcoin-cli: arguments privacy
---------------------------------
-
-The RPC command line client gained a new argument, `-stdin`
-to read extra arguments from standard input, one per line until EOF/Ctrl-D.
-For example:
-
- $ echo -e "mysecretcode\n120" | src/bitcoin-cli -stdin walletpassphrase
-
-It is recommended to use this for sensitive information such as wallet
-passphrases, as command-line arguments can usually be read from the process
-table by any user on the system.
-
-RPC low-level changes
-----------------------
-
-- `gettxoutsetinfo` UTXO hash (`hash_serialized`) has changed. There was a divergence between
- 32-bit and 64-bit platforms, and the txids were missing in the hashed data. This has been
- fixed, but this means that the output will be different than from previous versions.
-
-- Full UTF-8 support in the RPC API. Non-ASCII characters in, for example,
- wallet labels have always been malformed because they weren't taken into account
- properly in JSON RPC processing. This is no longer the case. This also affects
- the GUI debug console.
-
-C++11 and Python 3
--------------------
-
-Various code modernizations have been done. The Bitcoin Core code base has
-started using C++11. This means that a C++11-capable compiler is now needed for
-building. Effectively this means GCC 4.7 or higher, or Clang 3.3 or higher.
-
-When cross-compiling for a target that doesn't have C++11 libraries, configure with
-`./configure --enable-glibc-back-compat ... LDFLAGS=-static-libstdc++`.
-
-For running the functional tests in `qa/rpc-tests`, Python3.4 or higher is now
-required.
-
-Linux ARM builds
-------------------
-
-Due to popular request, Linux ARM builds have been added to the uploaded
-executables.
-
-The following extra files can be found in the download directory or torrent:
-
-- `bitcoin-${VERSION}-arm-linux-gnueabihf.tar.gz`: Linux binaries for the most
- common 32-bit ARM architecture.
-- `bitcoin-${VERSION}-aarch64-linux-gnu.tar.gz`: Linux binaries for the most
- common 64-bit ARM architecture.
-
-ARM builds are still experimental. If you have problems on a certain device or
-Linux distribution combination please report them on the bug tracker, it may be
-possible to resolve them.
-
-Note that Android is not considered ARM Linux in this context. The executables
-are not expected to work out of the box on Android.
-
-0.13.0 Change log
-=================
-
-Detailed release notes follow. This overview includes changes that affect
-behavior, not code moves, refactors and string updates. For convenience in locating
-the code changes and accompanying discussion, both the pull request and
-git merge commit are mentioned.
-
-### RPC and REST
-
-Asm script outputs replacements for OP_NOP2 and OP_NOP3
--------------------------------------------------------
-
-OP_NOP2 has been renamed to OP_CHECKLOCKTIMEVERIFY by [BIP
-65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki)
-
-OP_NOP3 has been renamed to OP_CHECKSEQUENCEVERIFY by [BIP
-112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki)
-
-The following outputs are affected by this change:
-- RPC `getrawtransaction` (in verbose mode)
-- RPC `decoderawtransaction`
-- RPC `decodescript`
-- REST `/rest/tx/` (JSON format)
-- REST `/rest/block/` (JSON format when including extended tx details)
-- `bitcoin-tx -json`
-
-New mempool information RPC calls
----------------------------------
-
-RPC calls have been added to output detailed statistics for individual mempool
-entries, as well as to calculate the in-mempool ancestors or descendants of a
-transaction: see `getmempoolentry`, `getmempoolancestors`, `getmempooldescendants`.
-
-### ZMQ
-
-Each ZMQ notification now contains an up-counting sequence number that allows
-listeners to detect lost notifications.
-The sequence number is always the last element in a multi-part ZMQ notification and
-therefore backward compatible.
-Each message type has its own counter.
-(https://github.com/bitcoin/bitcoin/pull/7762)
-
-### Configuration and command-line options
-
-### Block and transaction handling
-
-### P2P protocol and network code
-
-The p2p alert system has been removed in #7692 and the 'alert' message is no longer supported.
-
-
-Fee filtering of invs (BIP 133)
-------------------------------------
-
-The optional new p2p message "feefilter" is implemented and the protocol
-version is bumped to 70013. Upon receiving a feefilter message from a peer,
-a node will not send invs for any transactions which do not meet the filter
-feerate. [BIP 133](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki)
-
-### Validation
-
-### Build system
-
-### Wallet
-
-Hierarchical Deterministic Key Generation
------------------------------------------
-Newly created wallets will use hierarchical deterministic key generation
-according to BIP32 (keypath m/0'/0'/k').
-Existing wallets will still use traditional key generation.
-
-Backups of HD wallets, regardless of when they have been created, can
-therefore be used to re-generate all possible private keys, even the
-ones which haven't already been generated during the time of the backup.
-
-HD key generation for new wallets can be disabled by `-usehd=0`. Keep in
-mind that this flag only has affect on newly created wallets.
-You can't disable HD key generation once you have created a HD wallet.
-
-There is no distinction between internal (change) and external keys.
-
-[Pull request](https://github.com/bitcoin/bitcoin/pull/8035/files), [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
-
-### GUI
-
-### Tests
-
-### Miscellaneous
-
+Low-level RPC changes
+---------------------
+
+- Error codes have been updated to be more accurate for the following error cases:
+ - `getblock` now returns RPC_MISC_ERROR if the block can't be found on disk (for
+ example if the block has been pruned). Previously returned RPC_INTERNAL_ERROR.
+ - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned
+ because the node is not in pruned mode. Previously returned RPC_METHOD_NOT_FOUND.
+ - `pruneblockchain` now returns RPC_INVALID_PARAMETER if the blocks cannot be pruned
+ because the supplied timestamp is too late. Previously returned RPC_INTERNAL_ERROR.
+ - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned
+ because the blockchain is too short. Previously returned RPC_INTERNAL_ERROR.
+ - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the supplied IP address
+ or subnet is invalid. Previously returned RPC_CLIENT_NODE_ALREADY_ADDED.
+ - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the user tries to unban
+ a node that has not previously been banned. Previously returned RPC_MISC_ERROR.
+ - `removeprunedfunds` now returns RPC_WALLET_ERROR if bitcoind is unable to remove
+ the transaction. Previously returned RPC_INTERNAL_ERROR.
+ - `removeprunedfunds` now returns RPC_INVALID_PARAMETER if the transaction does not
+ exist in the wallet. Previously returned RPC_INTERNAL_ERROR.
+ - `fundrawtransaction` now returns RPC_INVALID_ADDRESS_OR_KEY if an invalid change
+ address is provided. Previously returned RPC_INVALID_PARAMETER.
+ - `fundrawtransaction` now returns RPC_WALLET_ERROR if bitcoind is unable to create
+ the transaction. The error message provides further details. Previously returned
+ RPC_INTERNAL_ERROR.
+ - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has
+ descendants in the wallet. Previously returned RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has
+ descendants in the mempool. Previously returned RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has
+ has been mined or conflicts with a mined transaction. Previously returned
+ RPC_INVALID_ADDRESS_OR_KEY.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction is not
+ BIP 125 replaceable. Previously returned RPC_INVALID_ADDRESS_OR_KEY.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has already
+ been bumped by a different transaction. Previously returned RPC_INVALID_REQUEST.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction contains
+ inputs which don't belong to this wallet. Previously returned RPC_INVALID_ADDRESS_OR_KEY.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has multiple change
+ outputs. Previously returned RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has no change
+ output. Previously returned RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too high. Previously returned
+ RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too low. Previously returned
+ RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the change output is too small to bump the
+ fee. Previously returned RPC_MISC_ERROR.
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
diff --git a/doc/release-notes/release-notes-0.12.1.md b/doc/release-notes/release-notes-0.12.1.md
new file mode 100644
index 0000000000..610cd481de
--- /dev/null
+++ b/doc/release-notes/release-notes-0.12.1.md
@@ -0,0 +1,198 @@
+Bitcoin Core version 0.12.1 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.12.1/>
+
+This is a new minor version release, including the BIP9, BIP68 and BIP112
+softfork, various bugfixes and updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+Upgrading and downgrading
+=========================
+
+How to Upgrade
+--------------
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes for older versions), then run the
+installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) or
+bitcoind/bitcoin-qt (on Linux).
+
+Downgrade warning
+-----------------
+
+### Downgrade to a version < 0.12.0
+
+Because release 0.12.0 and later will obfuscate the chainstate on every
+fresh sync or reindex, the chainstate is not backwards-compatible with
+pre-0.12 versions of Bitcoin Core or other software.
+
+If you want to downgrade after you have done a reindex with 0.12.0 or later,
+you will need to reindex when you first start Bitcoin Core version 0.11 or
+earlier.
+
+Notable changes
+===============
+
+First version bits BIP9 softfork deployment
+-------------------------------------------
+
+This release includes a soft fork deployment to enforce [BIP68][],
+[BIP112][] and [BIP113][] using the [BIP9][] deployment mechanism.
+
+The deployment sets the block version number to 0x20000001 between
+midnight 1st May 2016 and midnight 1st May 2017 to signal readiness for
+deployment. The version number consists of 0x20000000 to indicate version
+bits together with setting bit 0 to indicate support for this combined
+deployment, shown as "csv" in the `getblockchaininfo` RPC call.
+
+For more information about the soft forking change, please see
+<https://github.com/bitcoin/bitcoin/pull/7648>
+
+This specific backport pull-request can be viewed at
+<https://github.com/bitcoin/bitcoin/pull/7543>
+
+[BIP9]: https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki
+[BIP68]: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki
+[BIP112]: https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki
+[BIP113]: https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki
+
+BIP68 soft fork to enforce sequence locks for relative locktime
+---------------------------------------------------------------
+
+[BIP68][] introduces relative lock-time consensus-enforced semantics of
+the sequence number field to enable a signed transaction input to remain
+invalid for a defined period of time after confirmation of its corresponding
+outpoint.
+
+For more information about the implementation, see
+<https://github.com/bitcoin/bitcoin/pull/7184>
+
+BIP112 soft fork to enforce OP_CHECKSEQUENCEVERIFY
+--------------------------------------------------
+
+[BIP112][] redefines the existing OP_NOP3 as OP_CHECKSEQUENCEVERIFY (CSV)
+for a new opcode in the Bitcoin scripting system that in combination with
+[BIP68][] allows execution pathways of a script to be restricted based
+on the age of the output being spent.
+
+For more information about the implementation, see
+<https://github.com/bitcoin/bitcoin/pull/7524>
+
+BIP113 locktime enforcement soft fork
+-------------------------------------
+
+Bitcoin Core 0.11.2 previously introduced mempool-only locktime
+enforcement using GetMedianTimePast(). This release seeks to
+consensus enforce the rule.
+
+Bitcoin transactions currently may specify a locktime indicating when
+they may be added to a valid block. Current consensus rules require
+that blocks have a block header time greater than the locktime specified
+in any transaction in that block.
+
+Miners get to choose what time they use for their header time, with the
+consensus rule being that no node will accept a block whose time is more
+than two hours in the future. This creates a incentive for miners to
+set their header times to future values in order to include locktimed
+transactions which weren't supposed to be included for up to two more
+hours.
+
+The consensus rules also specify that valid blocks may have a header
+time greater than that of the median of the 11 previous blocks. This
+GetMedianTimePast() time has a key feature we generally associate with
+time: it can't go backwards.
+
+[BIP113][] specifies a soft fork enforced in this release that
+weakens this perverse incentive for individual miners to use a future
+time by requiring that valid blocks have a computed GetMedianTimePast()
+greater than the locktime specified in any transaction in that block.
+
+Mempool inclusion rules currently require transactions to be valid for
+immediate inclusion in a block in order to be accepted into the mempool.
+This release begins applying the BIP113 rule to received transactions,
+so transaction whose time is greater than the GetMedianTimePast() will
+no longer be accepted into the mempool.
+
+**Implication for miners:** you will begin rejecting transactions that
+would not be valid under BIP113, which will prevent you from producing
+invalid blocks when BIP113 is enforced on the network. Any
+transactions which are valid under the current rules but not yet valid
+under the BIP113 rules will either be mined by other miners or delayed
+until they are valid under BIP113. Note, however, that time-based
+locktime transactions are more or less unseen on the network currently.
+
+**Implication for users:** GetMedianTimePast() always trails behind the
+current time, so a transaction locktime set to the present time will be
+rejected by nodes running this release until the median time moves
+forward. To compensate, subtract one hour (3,600 seconds) from your
+locktimes to allow those transactions to be included in mempools at
+approximately the expected time.
+
+For more information about the implementation, see
+<https://github.com/bitcoin/bitcoin/pull/6566>
+
+Miscellaneous
+-------------
+
+The p2p alert system is off by default. To turn on, use `-alert` with
+startup configuration.
+
+0.12.1 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, refactors and string updates. For convenience in locating
+the code changes and accompanying discussion, both the pull request and
+git merge commit are mentioned.
+
+### RPC and other APIs
+- #7739 `7ffc2bd` Add abandoned status to listtransactions (jonasschnelli)
+
+### Block and transaction handling
+- #7543 `834aaef` Backport BIP9, BIP68 and BIP112 with softfork (btcdrak)
+
+### P2P protocol and network code
+- #7804 `90f1d24` Track block download times per individual block (sipa)
+- #7832 `4c3a00d` Reduce block timeout to 10 minutes (laanwj)
+
+### Validation
+- #7821 `4226aac` init: allow shutdown during 'Activating best chain...' (laanwj)
+- #7835 `46898e7` Version 2 transactions remain non-standard until CSV activates (sdaftuar)
+
+### Build system
+- #7487 `00d57b4` Workaround Travis-side CI issues (luke-jr)
+- #7606 `a10da9a` No need to set -L and --location for curl (MarcoFalke)
+- #7614 `ca8f160` Add curl to packages (now needed for depends) (luke-jr)
+- #7776 `a784675` Remove unnecessary executables from gitian release (laanwj)
+
+### Wallet
+- #7715 `19866c1` Fix calculation of balances and available coins. (morcos)
+
+### Miscellaneous
+- #7617 `f04f4fd` Fix markdown syntax and line terminate LogPrint (MarcoFalke)
+- #7747 `4d035bc` added depends cross compile info (accraze)
+- #7741 `a0cea89` Mark p2p alert system as deprecated (btcdrak)
+- #7780 `c5f94f6` Disable bad-chain alert (btcdrak)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- accraze
+- Alex Morcos
+- BtcDrak
+- Jonas Schnelli
+- Luke Dashjr
+- MarcoFalke
+- Mark Friedenbach
+- NicolasDorier
+- Pieter Wuille
+- Suhas Daftuar
+- Wladimir J. van der Laan
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
+
diff --git a/doc/release-notes/release-notes-0.13.0.md b/doc/release-notes/release-notes-0.13.0.md
new file mode 100644
index 0000000000..4c3cb97df3
--- /dev/null
+++ b/doc/release-notes/release-notes-0.13.0.md
@@ -0,0 +1,868 @@
+Bitcoin Core version 0.13.0 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.13.0/>
+
+This is a new major version release, including new features, various bugfixes
+and performance improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+Compatibility
+==============
+
+Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support),
+an OS initially released in 2001. This means that not even critical security
+updates will be released anymore. Without security updates, using a bitcoin
+wallet on a XP machine is irresponsible at least.
+
+In addition to that, with 0.12.x there have been varied reports of Bitcoin Core
+randomly crashing on Windows XP. It is [not clear](https://github.com/bitcoin/bitcoin/issues/7681#issuecomment-217439891)
+what the source of these crashes is, but it is likely that upstream
+libraries such as Qt are no longer being tested on XP.
+
+We do not have time nor resources to provide support for an OS that is
+end-of-life. From 0.13.0 on, Windows XP is no longer supported. Users are
+suggested to upgrade to a newer verion of Windows, or install an alternative OS
+that is supported.
+
+No attempt is made to prevent installing or running the software on Windows XP,
+you can still do so at your own risk, but do not expect it to work: do not
+report issues about Windows XP to the issue tracker.
+
+Notable changes
+===============
+
+Database cache memory increased
+--------------------------------
+
+As a result of growth of the UTXO set, performance with the prior default
+database cache of 100 MiB has suffered.
+For this reason the default was changed to 300 MiB in this release.
+
+For nodes on low-memory systems, the database cache can be changed back to
+100 MiB (or to another value) by either:
+
+- Adding `dbcache=100` in bitcoin.conf
+- Changing it in the GUI under `Options → Size of database cache`
+
+Note that the database cache setting has the most performance impact
+during initial sync of a node, and when catching up after downtime.
+
+
+bitcoin-cli: arguments privacy
+------------------------------
+
+The RPC command line client gained a new argument, `-stdin`
+to read extra arguments from standard input, one per line until EOF/Ctrl-D.
+For example:
+
+ $ src/bitcoin-cli -stdin walletpassphrase
+ mysecretcode
+ 120
+ ..... press Ctrl-D here to end input
+ $
+
+It is recommended to use this for sensitive information such as wallet
+passphrases, as command-line arguments can usually be read from the process
+table by any user on the system.
+
+
+C++11 and Python 3
+------------------
+
+Various code modernizations have been done. The Bitcoin Core code base has
+started using C++11. This means that a C++11-capable compiler is now needed for
+building. Effectively this means GCC 4.7 or higher, or Clang 3.3 or higher.
+
+When cross-compiling for a target that doesn't have C++11 libraries, configure with
+`./configure --enable-glibc-back-compat ... LDFLAGS=-static-libstdc++`.
+
+For running the functional tests in `qa/rpc-tests`, Python3.4 or higher is now
+required.
+
+
+Linux ARM builds
+----------------
+
+Due to popular request, Linux ARM builds have been added to the uploaded
+executables.
+
+The following extra files can be found in the download directory or torrent:
+
+- `bitcoin-${VERSION}-arm-linux-gnueabihf.tar.gz`: Linux binaries targeting
+ the 32-bit ARMv7-A architecture.
+- `bitcoin-${VERSION}-aarch64-linux-gnu.tar.gz`: Linux binaries targeting
+ the 64-bit ARMv8-A architecture.
+
+ARM builds are still experimental. If you have problems on a certain device or
+Linux distribution combination please report them on the bug tracker, it may be
+possible to resolve them. Note that the device you use must be (backward)
+compatible with the architecture targeted by the binary that you use.
+For example, a Raspberry Pi 2 Model B or Raspberry Pi 3 Model B (in its 32-bit
+execution state) device, can run the 32-bit ARMv7-A targeted binary. However,
+no model of Raspberry Pi 1 device can run either binary because they are all
+ARMv6 architecture devices that are not compatible with ARMv7-A or ARMv8-A.
+
+Note that Android is not considered ARM Linux in this context. The executables
+are not expected to work out of the box on Android.
+
+
+Compact Block support (BIP 152)
+-------------------------------
+
+Support for block relay using the Compact Blocks protocol has been implemented
+in PR 8068.
+
+The primary goal is reducing the bandwidth spikes at relay time, though in many
+cases it also reduces propagation delay. It is automatically enabled between
+compatible peers.
+[BIP 152](https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki)
+
+As a side-effect, ordinary non-mining nodes will download and upload blocks
+faster if those blocks were produced by miners using similar transaction
+filtering policies. This means that a miner who produces a block with many
+transactions discouraged by your node will be relayed slower than one with
+only transactions already in your memory pool. The overall effect of such
+relay differences on the network may result in blocks which include widely-
+discouraged transactions losing a stale block race, and therefore miners may
+wish to configure their node to take common relay policies into consideration.
+
+
+Hierarchical Deterministic Key Generation
+-----------------------------------------
+Newly created wallets will use hierarchical deterministic key generation
+according to BIP32 (keypath m/0'/0'/k').
+Existing wallets will still use traditional key generation.
+
+Backups of HD wallets, regardless of when they have been created, can
+therefore be used to re-generate all possible private keys, even the
+ones which haven't already been generated during the time of the backup.
+**Attention:** Encrypting the wallet will create a new seed which requires
+a new backup!
+
+Wallet dumps (created using the `dumpwallet` RPC) will contain the deterministic
+seed. This is expected to allow future versions to import the seed and all
+associated funds, but this is not yet implemented.
+
+HD key generation for new wallets can be disabled by `-usehd=0`. Keep in
+mind that this flag only has affect on newly created wallets.
+You can't disable HD key generation once you have created a HD wallet.
+
+There is no distinction between internal (change) and external keys.
+
+HD wallets are incompatible with older versions of Bitcoin Core.
+
+[Pull request](https://github.com/bitcoin/bitcoin/pull/8035/files), [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
+
+
+Segregated Witness
+------------------
+
+The code preparations for Segregated Witness ("segwit"), as described in [BIP
+141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki), [BIP
+143](https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki), [BIP
+144](https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki), and [BIP
+145](https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki) are
+finished and included in this release. However, BIP 141 does not yet specify
+activation parameters on mainnet, and so this release does not support segwit
+use on mainnet. Testnet use is supported, and after BIP 141 is updated with
+proposed parameters, a future release of Bitcoin Core is expected that
+implements those parameters for mainnet.
+
+Furthermore, because segwit activation is not yet specified for mainnet,
+version 0.13.0 will behave similarly as other pre-segwit releases even after a
+future activation of BIP 141 on the network. Upgrading from 0.13.0 will be
+required in order to utilize segwit-related features on mainnet (such as signal
+BIP 141 activation, mine segwit blocks, fully validate segwit blocks, relay
+segwit blocks to other segwit nodes, and use segwit transactions in the
+wallet, etc).
+
+
+Mining transaction selection ("Child Pays For Parent")
+------------------------------------------------------
+
+The mining transaction selection algorithm has been replaced with an algorithm
+that selects transactions based on their feerate inclusive of unconfirmed
+ancestor transactions. This means that a low-fee transaction can become more
+likely to be selected if a high-fee transaction that spends its outputs is
+relayed.
+
+With this change, the `-blockminsize` command line option has been removed.
+
+The command line option `-blockmaxsize` remains an option to specify the
+maximum number of serialized bytes in a generated block. In addition, the new
+command line option `-blockmaxweight` has been added, which specifies the
+maximum "block weight" of a generated block, as defined by [BIP 141 (Segregated
+Witness)] (https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki).
+
+In preparation for Segregated Witness, the mining algorithm has been modified
+to optimize transaction selection for a given block weight, rather than a given
+number of serialized bytes in a block. In this release, transaction selection
+is unaffected by this distinction (as BIP 141 activation is not supported on
+mainnet in this release, see above), but in future releases and after BIP 141
+activation, these calculations would be expected to differ.
+
+For optimal runtime performance, miners using this release should specify
+`-blockmaxweight` on the command line, and not specify `-blockmaxsize`.
+Additionally (or only) specifying `-blockmaxsize`, or relying on default
+settings for both, may result in performance degradation, as the logic to
+support `-blockmaxsize` performs additional computation to ensure that
+constraint is met. (Note that for mainnet, in this release, the equivalent
+parameter for `-blockmaxweight` would be four times the desired
+`-blockmaxsize`. See [BIP 141]
+(https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki) for additional
+details.)
+
+In the future, the `-blockmaxsize` option may be removed, as block creation is
+no longer optimized for this metric. Feedback is requested on whether to
+deprecate or keep this command line option in future releases.
+
+
+Reindexing changes
+------------------
+
+In earlier versions, reindexing did validation while reading through the block
+files on disk. These two have now been split up, so that all blocks are known
+before validation starts. This was necessary to make certain optimizations that
+are available during normal synchronizations also available during reindexing.
+
+The two phases are distinct in the Bitcoin-Qt GUI. During the first one,
+"Reindexing blocks on disk" is shown. During the second (slower) one,
+"Processing blocks on disk" is shown.
+
+It is possible to only redo validation now, without rebuilding the block index,
+using the command line option `-reindex-chainstate` (in addition to
+`-reindex` which does both). This new option is useful when the blocks on disk
+are assumed to be fine, but the chainstate is still corrupted. It is also
+useful for benchmarks.
+
+
+Removal of internal miner
+--------------------------
+
+As CPU mining has been useless for a long time, the internal miner has been
+removed in this release, and replaced with a simpler implementation for the
+test framework.
+
+The overall result of this is that `setgenerate` RPC call has been removed, as
+well as the `-gen` and `-genproclimit` command-line options.
+
+For testing, the `generate` call can still be used to mine a block, and a new
+RPC call `generatetoaddress` has been added to mine to a specific address. This
+works with wallet disabled.
+
+
+New bytespersigop implementation
+--------------------------------
+
+The former implementation of the bytespersigop filter accidentally broke bare
+multisig (which is meant to be controlled by the `permitbaremultisig` option),
+since the consensus protocol always counts these older transaction forms as 20
+sigops for backwards compatibility. Simply fixing this bug by counting more
+accurately would have reintroduced a vulnerability. It has therefore been
+replaced with a new implementation that rather than filter such transactions,
+instead treats them (for fee purposes only) as if they were in fact the size
+of a transaction actually using all 20 sigops.
+
+
+Low-level P2P changes
+----------------------
+
+- The optional new p2p message "feefilter" is implemented and the protocol
+ version is bumped to 70013. Upon receiving a feefilter message from a peer,
+ a node will not send invs for any transactions which do not meet the filter
+ feerate. [BIP 133](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki)
+
+- The P2P alert system has been removed in PR #7692 and the `alert` P2P message
+ is no longer supported.
+
+- The transaction relay mechanism used to relay one quarter of all transactions
+ instantly, while queueing up the rest and sending them out in batch. As
+ this resulted in chains of dependent transactions being reordered, it
+ systematically hurt transaction relay. The relay code was redesigned in PRs
+ \#7840 and #8082, and now always batches transactions announcements while also
+ sorting them according to dependency order. This significantly reduces orphan
+ transactions. To compensate for the removal of instant relay, the frequency of
+ batch sending was doubled for outgoing peers.
+
+- Since PR #7840 the BIP35 `mempool` command is also subject to batch processing.
+ Also the `mempool` message is no longer handled for non-whitelisted peers when
+ `NODE_BLOOM` is disabled through `-peerbloomfilters=0`.
+
+- The maximum size of orphan transactions that are kept in memory until their
+ ancestors arrive has been raised in PR #8179 from 5000 to 99999 bytes. They
+ are now also removed from memory when they are included in a block, conflict
+ with a block, and time out after 20 minutes.
+
+- We respond at most once to a getaddr request during the lifetime of a
+ connection since PR #7856.
+
+- Connections to peers who have recently been the first one to give us a valid
+ new block or transaction are protected from disconnections since PR #8084.
+
+
+Low-level RPC changes
+----------------------
+
+- RPC calls have been added to output detailed statistics for individual mempool
+ entries, as well as to calculate the in-mempool ancestors or descendants of a
+ transaction: see `getmempoolentry`, `getmempoolancestors`, `getmempooldescendants`.
+
+- `gettxoutsetinfo` UTXO hash (`hash_serialized`) has changed. There was a divergence between
+ 32-bit and 64-bit platforms, and the txids were missing in the hashed data. This has been
+ fixed, but this means that the output will be different than from previous versions.
+
+- Full UTF-8 support in the RPC API. Non-ASCII characters in, for example,
+ wallet labels have always been malformed because they weren't taken into account
+ properly in JSON RPC processing. This is no longer the case. This also affects
+ the GUI debug console.
+
+- Asm script outputs replacements for OP_NOP2 and OP_NOP3
+
+ - OP_NOP2 has been renamed to OP_CHECKLOCKTIMEVERIFY by [BIP
+65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki)
+
+ - OP_NOP3 has been renamed to OP_CHECKSEQUENCEVERIFY by [BIP
+112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki)
+
+ - The following outputs are affected by this change:
+
+ - RPC `getrawtransaction` (in verbose mode)
+ - RPC `decoderawtransaction`
+ - RPC `decodescript`
+ - REST `/rest/tx/` (JSON format)
+ - REST `/rest/block/` (JSON format when including extended tx details)
+ - `bitcoin-tx -json`
+
+- The sorting of the output of the `getrawmempool` output has changed.
+
+- New RPC commands: `generatetoaddress`, `importprunedfunds`, `removeprunedfunds`, `signmessagewithprivkey`,
+ `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry`,
+ `createwitnessaddress`, `addwitnessaddress`.
+
+- Removed RPC commands: `setgenerate`, `getgenerate`.
+
+- New options were added to `fundrawtransaction`: `includeWatching`, `changeAddress`, `changePosition` and `feeRate`.
+
+
+Low-level ZMQ changes
+----------------------
+
+- Each ZMQ notification now contains an up-counting sequence number that allows
+ listeners to detect lost notifications.
+ The sequence number is always the last element in a multi-part ZMQ notification and
+ therefore backward compatible. Each message type has its own counter.
+ PR [#7762](https://github.com/bitcoin/bitcoin/pull/7762).
+
+
+0.13.0 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, refactors and string updates. For convenience in locating
+the code changes and accompanying discussion, both the pull request and
+git merge commit are mentioned.
+
+### RPC and other APIs
+
+- #7156 `9ee02cf` Remove cs_main lock from `createrawtransaction` (laanwj)
+- #7326 `2cd004b` Fix typo, wrong information in gettxout help text (paveljanik)
+- #7222 `82429d0` Indicate which transactions are signaling opt-in RBF (sdaftuar)
+- #7480 `b49a623` Changed getnetworkhps value to double to avoid overflow (instagibbs)
+- #7550 `8b958ab` Input-from-stdin mode for bitcoin-cli (laanwj)
+- #7670 `c9a1265` Use cached block hash in blockToJSON() (rat4)
+- #7726 `9af69fa` Correct importaddress help reference to importpubkey (CypherGrue)
+- #7766 `16555b6` Register calls where they are defined (laanwj)
+- #7797 `e662a76` Fix generatetoaddress failing to parse address (mruddy)
+- #7774 `916b15a` Add versionHex in getblock and getblockheader JSON results (mruddy)
+- #7863 `72c54e3` Getblockchaininfo: make bip9_softforks an object, not an array (rustyrussell)
+- #7842 `d97101e` Do not print minping time in getpeerinfo when no ping received yet (paveljanik)
+- #7518 `be14ca5` Add multiple options to fundrawtransaction (promag)
+- #7756 `9e47fce` Add cursor to iterate over utxo set, use this in `gettxoutsetinfo` (laanwj)
+- #7848 `88616d2` Divergence between 32- and 64-bit when hashing >4GB affects `gettxoutsetinfo` (laanwj)
+- #7827 `4205ad7` Speed up `getchaintips` (mrbandrews)
+- #7762 `a1eb344` Append a message sequence number to every ZMQ notification (jonasschnelli)
+- #7688 `46880ed` List solvability in listunspent output and improve help (sipa)
+- #7926 `5725807` Push back `getaddednodeinfo` dead value (instagibbs)
+- #7953 `0630353` Create `signmessagewithprivkey` rpc (achow101)
+- #8049 `c028c7b` Expose information on whether transaction relay is enabled in `getnetworkinfo` (laanwj)
+- #7967 `8c1e49b` Add feerate option to `fundrawtransaction` (jonasschnelli)
+- #8118 `9b6a48c` Reduce unnecessary hashing in `signrawtransaction` (jonasnick)
+- #7957 `79004d4` Add support for transaction sequence number (jonasschnelli)
+- #8153 `75ec320` `fundrawtransaction` feeRate: Use BTC/kB (MarcoFalke)
+- #7292 `7ce9ac5` Expose ancestor/descendant information over RPC (sdaftuar)
+- #8171 `62fcf27` Fix createrawtx sequence number unsigned int parsing (jonasschnelli)
+- #7892 `9c3d0fa` Add full UTF-8 support to RPC (laanwj)
+- #8317 `304eff3` Don't use floating point in rpcwallet (MarcoFalke)
+- #8258 `5a06ebb` Hide softfork in `getblockchaininfo` if timeout is 0 (jl2012)
+- #8244 `1922e5a` Remove unnecessary LOCK(cs_main) in getrawmempool (dcousens)
+
+### Block and transaction handling
+
+- #7056 `6a07208` Save last db read (morcos)
+- #6842 `0192806` Limitfreerelay edge case bugfix (ptschip)
+- #7084 `11d74f6` Replace maxFeeRate of 10000*minRelayTxFee with maxTxFee in mempool (MarcoFalke)
+- #7539 `9f33dba` Add tags to mempool's mapTx indices (sdaftuar)
+- #7592 `26a2a72` Re-remove ERROR logging for mempool rejects (laanwj)
+- #7187 `14d6324` Keep reorgs fast for SequenceLocks checks (morcos)
+- #7594 `01f4267` Mempool: Add tracking of ancestor packages (sdaftuar)
+- #7904 `fc9e334` Txdb: Fix assert crash in new UTXO set cursor (laanwj)
+- #7927 `f9c2ac7` Minor changes to dbwrapper to simplify support for other databases (laanwj)
+- #7933 `e26b620` Fix OOM when deserializing UTXO entries with invalid length (sipa)
+- #8020 `5e374f7` Use SipHash-2-4 for various non-cryptographic hashes (sipa)
+- #8076 `d720980` VerifyDB: don't check blocks that have been pruned (sdaftuar)
+- #8080 `862fd24` Do not use mempool for GETDATA for tx accepted after the last mempool req (gmaxwell)
+- #7997 `a82f033` Replace mapNextTx with slimmer setSpends (kazcw)
+- #8220 `1f86d64` Stop trimming when mapTx is empty (sipa)
+- #8273 `396f9d6` Bump `-dbcache` default to 300MiB (laanwj)
+- #7225 `eb33179` Eliminate unnecessary call to CheckBlock (sdaftuar)
+- #7907 `006cdf6` Optimize and Cleanup CScript::FindAndDelete (pstratem)
+- #7917 `239d419` Optimize reindex (sipa)
+- #7763 `3081fb9` Put hex-encoded version in UpdateTip (sipa)
+- #8149 `d612837` Testnet-only segregated witness (sipa)
+- #8305 `3730393` Improve handling of unconnecting headers (sdaftuar)
+- #8363 `fca1a41` Rename "block cost" to "block weight" (sdaftuar)
+- #8381 `f84ee3d` Make witness v0 outputs non-standard (jl2012)
+- #8364 `3f65ba2` Treat high-sigop transactions as larger rather than rejecting them (sipa)
+
+### P2P protocol and network code
+
+- #6589 `dc0305d` Log bytes recv/sent per command (jonasschnelli)
+- #7164 `3b43cad` Do not download transactions during initial blockchain sync (ptschip)
+- #7458 `898fedf` peers.dat, banlist.dat recreated when missing (kirkalx)
+- #7637 `3da5d1b` Fix memleak in TorController (laanwj, jonasschnelli)
+- #7553 `9f14e5a` Remove vfReachable and modify IsReachable to only use vfLimited (pstratem)
+- #7708 `9426632` De-neuter NODE_BLOOM (pstratem)
+- #7692 `29b2be6` Remove P2P alert system (btcdrak)
+- #7542 `c946a15` Implement "feefilter" P2P message (morcos)
+- #7573 `352fd57` Add `-maxtimeadjustment` command line option (mruddy)
+- #7570 `232592a` Add IPv6 Link-Local Address Support (mruddy)
+- #7874 `e6a4d48` Improve AlreadyHave (morcos)
+- #7856 `64e71b3` Only send one GetAddr response per connection (gmaxwell)
+- #7868 `7daa3ad` Split DNS resolving functionality out of net structures (theuni)
+- #7919 `7617682` Fix headers announcements edge case (sdaftuar)
+- #7514 `d9594bf` Fix IsInitialBlockDownload for testnet (jmacwhyte)
+- #7959 `03cf6e8` fix race that could fail to persist a ban (kazcw)
+- #7840 `3b9a0bf` Several performance and privacy improvements to inv/mempool handling (sipa)
+- #8011 `65aecda` Don't run ThreadMessageHandler at lowered priority (kazcw)
+- #7696 `5c3f8dd` Fix de-serialization bug where AddrMan is left corrupted (EthanHeilman)
+- #7932 `ed749bd` CAddrMan::Deserialize handle corrupt serializations better (pstratem)
+- #7906 `83121cc` Prerequisites for p2p encapsulation changes (theuni)
+- #8033 `18436d8` Fix Socks5() connect failures to be less noisy and less unnecessarily scary (wtogami)
+- #8082 `01d8359` Defer inserting into maprelay until just before relaying (gmaxwell)
+- #7960 `6a22373` Only use AddInventoryKnown for transactions (sdaftuar)
+- #8078 `2156fa2` Disable the mempool P2P command when bloom filters disabled (petertodd)
+- #8065 `67c91f8` Addrman offline attempts (gmaxwell)
+- #7703 `761cddb` Tor: Change auth order to only use password auth if -torpassword (laanwj)
+- #8083 `cd0c513` Add support for dnsseeds with option to filter by servicebits (jonasschnelli)
+- #8173 `4286f43` Use SipHash for node eviction (sipa)
+- #8154 `1445835` Drop vAddrToSend after sending big addr message (kazcw)
+- #7749 `be9711e` Enforce expected outbound services (sipa)
+- #8208 `0a64777` Do not set extra flags for unfiltered DNS seed results (sipa)
+- #8084 `e4bb4a8` Add recently accepted blocks and txn to AttemptToEvictConnection (gmaxwell)
+- #8113 `3f89a53` Rework addnode behaviour (sipa)
+- #8179 `94ab58b` Evict orphans which are included or precluded by accepted blocks (gmaxwell)
+- #8068 `e9d76a1` Compact Blocks (TheBlueMatt)
+- #8204 `0833894` Update petertodd's testnet seed (petertodd)
+- #8247 `5cd35d3` Mark my dnsseed as supporting filtering (sipa)
+- #8275 `042c323` Remove bad chain alert partition check (btcdrak)
+- #8271 `1bc9c80` Do not send witnesses in cmpctblock (sipa)
+- #8312 `ca40ef6` Fix mempool DoS vulnerability from malleated transactions (sdaftuar)
+- #7180 `16ccb74` Account for `sendheaders` `verack` messages (laanwj)
+- #8102 `425278d` Bugfix: use global ::fRelayTxes instead of CNode in version send (sipa)
+- #8408 `b7e2011` Prevent fingerprinting, disk-DoS with compact blocks (sdaftuar)
+
+### Build system
+
+- #7302 `41f1a3e` C++11 build/runtime fixes (theuni)
+- #7322 `fd9356b` c++11: add scoped enum fallbacks to CPPFLAGS rather than defining them locally (theuni)
+- #7441 `a6771fc` Use Debian 8.3 in gitian build guide (fanquake)
+- #7349 `152a821` Build against system UniValue when available (luke-jr)
+- #7520 `621940e` LibreSSL doesn't define OPENSSL_VERSION, use LIBRESSL_VERSION_TEXT instead (paveljanik)
+- #7528 `9b9bfce` autogen.sh: warn about needing autoconf if autoreconf is not found (knocte)
+- #7504 `19324cf` Crystal clean make clean (paveljanik)
+- #7619 `18b3f1b` Add missing sudo entry in gitian VM setup (btcdrak)
+- #7616 `639ec58` [depends] Delete unused patches (MarcoFalke)
+- #7658 `c15eb28` Add curl to Gitian setup instructions (btcdrak)
+- #7710 `909b72b` [Depends] Bump miniupnpc and config.guess+sub (fanquake)
+- #7723 `5131005` build: python 3 compatibility (laanwj)
+- #7477 `28ad4d9` Fix quoting of copyright holders in configure.ac (domob1812)
+- #7711 `a67bc5e` [build-aux] Update Boost & check macros to latest serials (fanquake)
+- #7788 `4dc1b3a` Use relative paths instead of absolute paths in protoc calls (paveljanik)
+- #7809 `bbd210d` depends: some base fixes/changes (theuni)
+- #7603 `73fc922` Build System: Use PACKAGE_TARNAME in NSIS script (JeremyRand)
+- #7905 `187186b` test: move accounting_tests and rpc_wallet_tests to wallet/test (laanwj)
+- #7911 `351abf9` leveldb: integrate leveldb into our buildsystem (theuni)
+- #7944 `a407807` Re-instate TARGET_OS=linux in configure.ac. Removed by 351abf9e035 (randy-waterhouse)
+- #7920 `c3e3cfb` Switch Travis to Trusty (theuni)
+- #7954 `08b37c5` build: quiet annoying warnings without adding new ones (theuni)
+- #7165 `06162f1` build: Enable C++11 in build, require C++11 compiler (laanwj)
+- #7982 `559fbae` build: No need to check for leveldb atomics (theuni)
+- #8002 `f9b4582` [depends] Add -stdlib=libc++ to darwin CXX flags (fanquake)
+- #7993 `6a034ed` [depends] Bump Freetype, ccache, ZeroMQ, miniupnpc, expat (fanquake)
+- #8167 `19ea173` Ship debug tarballs/zips with debug symbols (theuni)
+- #8175 `f0299d8` Add --disable-bench to config flags for windows (laanwj)
+- #7283 `fd9881a` [gitian] Default reference_datetime to commit author date (MarcoFalke)
+- #8181 `9201ce8` Get rid of `CLIENT_DATE` (laanwj)
+- #8133 `fde0ac4` Finish up out-of-tree changes (theuni)
+- #8188 `65a9d7d` Add armhf/aarch64 gitian builds (theuni)
+- #8194 `cca1c8c` [gitian] set correct PATH for wrappers (MarcoFalke)
+- #8198 `5201614` Sync ax_pthread with upstream draft4 (fanquake)
+- #8210 `12a541e` [Qt] Bump to Qt5.6.1 (jonasschnelli)
+- #8285 `da50997` windows: Add testnet link to installer (laanwj)
+- #8304 `0cca2fe` [travis] Update SDK_URL (MarcoFalke)
+- #8310 `6ae20df` Require boost for bench (theuni)
+- #8315 `2e51590` Don't require sudo for Linux (theuni)
+- #8314 `67caef6` Fix pkg-config issues for 0.13 (theuni)
+- #8373 `1fe7f40` Fix OSX non-deterministic dmg (theuni)
+- #8358 `cfd1280` Gbuild: Set memory explicitly (default is too low) (MarcoFalke)
+
+### GUI
+
+- #7154 `00b4b8d` Add InMempool() info to transaction details (jonasschnelli)
+- #7068 `5f3c670` [RPC-Tests] add simple way to run rpc test over QT clients (jonasschnelli)
+- #7218 `a1c185b` Fix misleading translation (MarcoFalke)
+- #7214 `be9a9a3` qt5: Use the fixed font the system recommends (MarcoFalke)
+- #7256 `08ab906` Add note to coin control dialog QT5 workaround (fanquake)
+- #7255 `e289807` Replace some instances of formatWithUnit with formatHtmlWithUnit (fanquake)
+- #7317 `3b57e9c` Fix RPCTimerInterface ordering issue (jonasschnelli)
+- #7327 `c079d79` Transaction View: LastMonth calculation fixed (crowning-)
+- #7334 `e1060c5` coincontrol workaround is still needed in qt5.4 (fixed in qt5.5) (MarcoFalke)
+- #7383 `ae2db67` Rename "amount" to "requested amount" in receive coins table (jonasschnelli)
+- #7396 `cdcbc59` Add option to increase/decrease font size in the console window (jonasschnelli)
+- #7437 `9645218` Disable tab navigation for peers tables (Kefkius)
+- #7604 `354b03d` build: Remove spurious dollar sign. Fixes #7189 (dooglus)
+- #7605 `7f001bd` Remove openssl info from init/log and from Qt debug window (jonasschnelli)
+- #7628 `87d6562` Add 'copy full transaction details' option (ericshawlinux)
+- #7613 `3798e5d` Add autocomplete to bitcoin-qt's console window (GamerSg)
+- #7668 `b24266c` Fix history deletion bug after font size change (achow101)
+- #7680 `41d2dfa` Remove reflection from `about` icon (laanwj)
+- #7686 `f034bce` Remove 0-fee from send dialog (MarcoFalke)
+- #7506 `b88e0b0` Use CCoinControl selection in CWallet::FundTransaction (promag)
+- #7732 `0b98dd7` Debug window: replace "Build date" with "Datadir" (jonasschnelli)
+- #7761 `60db51d` remove trailing output-index from transaction-id (jonasschnelli)
+- #7772 `6383268` Clear the input line after activating autocomplete (paveljanik)
+- #7925 `f604bf6` Fix out-of-tree GUI builds (laanwj)
+- #7939 `574ddc6` Make it possible to show details for multiple transactions (laanwj)
+- #8012 `b33824b` Delay user confirmation of send (Tyler-Hardin)
+- #8006 `7c8558d` Add option to disable the system tray icon (Tyler-Hardin)
+- #8046 `169d379` Fix Cmd-Q / Menu Quit shutdown on OSX (jonasschnelli)
+- #8042 `6929711` Don't allow to open the debug window during splashscreen & verification state (jonasschnelli)
+- #8014 `77b49ac` Sort transactions by date (Tyler-Hardin)
+- #8073 `eb2f6f7` askpassphrasedialog: Clear pass fields on accept (rat4)
+- #8129 `ee1533e` Fix RPC console auto completer (UdjinM6)
+- #7636 `fb0ac48` Add bitcoin address label to request payment QR code (makevoid)
+- #8231 `760a6c7` Fix a bug where the SplashScreen will not be hidden during startup (jonasschnelli)
+- #8256 `af2421c` BUG: bitcoin-qt crash (fsb4000)
+- #8257 `ff03c50` Do not ask a UI question from bitcoind (sipa)
+- #8288 `91abb77` Network-specific example address (laanwj)
+- #7707 `a914968` UI support for abandoned transactions (jonasschnelli)
+- #8207 `f7a403b` Add a link to the Bitcoin-Core repository and website to the About Dialog (MarcoFalke)
+- #8281 `6a87eb0` Remove client name from debug window (laanwj)
+- #8407 `45eba4b` Add dbcache migration path (jonasschnelli)
+
+### Wallet
+
+- #7262 `fc08994` Reduce inefficiency of GetAccountAddress() (dooglus)
+- #7537 `78e81b0` Warn on unexpected EOF while salvaging wallet (laanwj)
+- #7521 `3368895` Don't resend wallet txs that aren't in our own mempool (morcos)
+- #7576 `86a1ec5` Move wallet help string creation to CWallet (jonasschnelli)
+- #7577 `5b3b5a7` Move "load wallet phase" to CWallet (jonasschnelli)
+- #7608 `0735c0c` Move hardcoded file name out of log messages (MarcoFalke)
+- #7649 `4900641` Prevent multiple calls to CWallet::AvailableCoins (promag)
+- #7646 `e5c3511` Fix lockunspent help message (promag)
+- #7558 `b35a591` Add import/removeprunedfunds rpc call (instagibbs)
+- #6215 `48c5adf` add bip32 pub key serialization (jonasschnelli)
+- #7913 `bafd075` Fix for incorrect locking in GetPubKey() (keystore.cpp) (yurizhykin)
+- #8036 `41138f9` init: Move berkeleydb version reporting to wallet (laanwj)
+- #8028 `373b50d` Fix insanity of CWalletDB::WriteTx and CWalletTx::WriteToDisk (pstratem)
+- #8061 `f6b7df3` Improve Wallet encapsulation (pstratem)
+- #7891 `950be19` Always require OS randomness when generating secret keys (sipa)
+- #7689 `b89ef13` Replace OpenSSL AES with ctaes-based version (sipa)
+- #7825 `f972b04` Prevent multiple calls to ExtractDestination (pedrobranco)
+- #8137 `243ac0c` Improve CWallet API with new AccountMove function (pstratem)
+- #8142 `52c3f34` Improve CWallet API with new GetAccountPubkey function (pstratem)
+- #8035 `b67a472` Add simplest BIP32/deterministic key generation implementation (jonasschnelli)
+- #7687 `a6ddb19` Stop treating importaddress'ed scripts as change (sipa)
+- #8298 `aef3811` wallet: Revert input selection post-pruning (laanwj)
+- #8324 `bc94b87` Keep HD seed during salvagewallet (jonasschnelli)
+- #8323 `238300b` Add HD keypath to CKeyMetadata, report metadata in validateaddress (jonasschnelli)
+- #8367 `3b38a6a` Ensure <0.13 clients can't open HD wallets (jonasschnelli)
+- #8378 `ebea651` Move SetMinVersion for FEATURE_HD to SetHDMasterKey (pstratem)
+- #8390 `73adfe3` Correct hdmasterkeyid/masterkeyid name confusion (jonasschnelli)
+- #8206 `18b8ee1` Add HD xpriv to dumpwallet (jonasschnelli)
+- #8389 `c3c82c4` Create a new HD seed after encrypting the wallet (jonasschnelli)
+
+### Tests and QA
+
+- #7320 `d3dfc6d` Test walletpassphrase timeout (MarcoFalke)
+- #7208 `47c5ed1` Make max tip age an option instead of chainparam (laanwj)
+- #7372 `21376af` Trivial: [qa] wallet: Print maintenance (MarcoFalke)
+- #7280 `668906f` [travis] Fail when documentation is outdated (MarcoFalke)
+- #7177 `93b0576` [qa] Change default block priority size to 0 (MarcoFalke)
+- #7236 `02676c5` Use createrawtx locktime parm in txn_clone (dgenr8)
+- #7212 `326ffed` Adds unittests for CAddrMan and CAddrinfo, removes source of non-determinism (EthanHeilman)
+- #7490 `d007511` tests: Remove May15 test (laanwj)
+- #7531 `18cb2d5` Add bip68-sequence.py to extended rpc tests (btcdrak)
+- #7536 `ce5fc02` test: test leading spaces for ParseHex (laanwj)
+- #7620 `1b68de3` [travis] Only run check-doc.py once (MarcoFalke)
+- #7455 `7f96671` [travis] Exit early when check-doc.py fails (MarcoFalke)
+- #7667 `56d2c4e` Move GetTempPath() to testutil (musalbas)
+- #7517 `f1ca891` test: script_error checking in script_invalid tests (laanwj)
+- #7684 `3d0dfdb` Extend tests (MarcoFalke)
+- #7697 `622fe6c` Tests: make prioritise_transaction.py more robust (sdaftuar)
+- #7709 `efde86b` Tests: fix missing import in mempool_packages (sdaftuar)
+- #7702 `29e1131` Add tests verifychain, lockunspent, getbalance, listsinceblock (MarcoFalke)
+- #7720 `3b4324b` rpc-test: Normalize assert() (MarcoFalke)
+- #7757 `26794d4` wallet: Wait for reindex to catch up (MarcoFalke)
+- #7764 `a65b36c` Don't run pruning.py twice (MarcoFalke)
+- #7773 `7c80e72` Fix comments in tests (btcdrak)
+- #7489 `e9723cb` tests: Make proxy_test work on travis servers without IPv6 (laanwj)
+- #7801 `70ac71b` Remove misleading "errorString syntax" (MarcoFalke)
+- #7803 `401c65c` maxblocksinflight: Actually enable test (MarcoFalke)
+- #7802 `3bc71e1` httpbasics: Actually test second connection (MarcoFalke)
+- #7849 `ab8586e` tests: add varints_bitpatterns test (laanwj)
+- #7846 `491171f` Clean up lockorder data of destroyed mutexes (sipa)
+- #7853 `6ef5e00` py2: Unfiddle strings into bytes explicitly (MarcoFalke)
+- #7878 `53adc83` [test] bctest.py: Revert faa41ee (MarcoFalke)
+- #7798 `cabba24` [travis] Print the commit which was evaluated (MarcoFalke)
+- #7833 `b1bf511` tests: Check Content-Type header returned from RPC server (laanwj)
+- #7851 `fa9d86f` pull-tester: Don't mute zmq ImportError (MarcoFalke)
+- #7822 `0e6fd5e` Add listunspent() test for spendable/unspendable UTXO (jpdffonseca)
+- #7912 `59ad568` Tests: Fix deserialization of reject messages (sdaftuar)
+- #7941 `0ea3941` Fixing comment in script_test.json test case (Christewart)
+- #7807 `0ad1041` Fixed miner test values, gave constants for less error-prone values (instagibbs)
+- #7980 `88b77c7` Smartfees: Properly use ordered dict (MarcoFalke)
+- #7814 `77b637f` Switch to py3 (MarcoFalke)
+- #8030 `409a8a1` Revert fatal-ness of missing python-zmq (laanwj)
+- #8018 `3e90fe6` Autofind rpc tests --srcdir (jonasschnelli)
+- #8016 `5767e80` Fix multithread CScheduler and reenable test (paveljanik)
+- #7972 `423ca30` pull-tester: Run rpc test in parallel (MarcoFalke)
+- #8039 `69b3a6d` Bench: Add crypto hash benchmarks (laanwj)
+- #8041 `5b736dd` Fix bip9-softforks blockstore issue (MarcoFalke)
+- #7994 `1f01443` Add op csv tests to script_tests.json (Christewart)
+- #8038 `e2bf830` Various minor fixes (MarcoFalke)
+- #8072 `1b87e5b` Travis: 'make check' in parallel and verbose (theuni)
+- #8056 `8844ef1` Remove hardcoded "4 nodes" from test_framework (MarcoFalke)
+- #8047 `37f9a1f` Test_framework: Set wait-timeout for bitcoind procs (MarcoFalke)
+- #8095 `6700cc9` Test framework: only cleanup on successful test runs (sdaftuar)
+- #8098 `06bd4f6` Test_framework: Append portseed to tmpdir (MarcoFalke)
+- #8104 `6ff2c8d` Add timeout to sync_blocks() and sync_mempools() (sdaftuar)
+- #8111 `61b8684` Benchmark SipHash (sipa)
+- #8107 `52b803e` Bench: Added base58 encoding/decoding benchmarks (yurizhykin)
+- #8115 `0026e0e` Avoid integer division in the benchmark inner-most loop (gmaxwell)
+- #8090 `a2df115` Adding P2SH(p2pkh) script test case (Christewart)
+- #7992 `ec45cc5` Extend #7956 with one more test (TheBlueMatt)
+- #8139 `ae5575b` Fix interrupted HTTP RPC connection workaround for Python 3.5+ (sipa)
+- #8164 `0f24eaf` [Bitcoin-Tx] fix missing test fixtures, fix 32bit atoi issue (jonasschnelli)
+- #8166 `0b5279f` Src/test: Do not shadow local variables (paveljanik)
+- #8141 `44c1b1c` Continuing port of java comparison tool (mrbandrews)
+- #8201 `36b7400` fundrawtransaction: Fix race, assert amounts (MarcoFalke)
+- #8214 `ed2cd59` Mininode: fail on send_message instead of silent return (MarcoFalke)
+- #8215 `a072d1a` Don't use floating point in wallet tests (MarcoFalke)
+- #8066 `65c2058` Test_framework: Use different rpc_auth_pair for each node (MarcoFalke)
+- #8216 `0d41d70` Assert 'changePosition out of bounds' (MarcoFalke)
+- #8222 `961893f` Enable mempool consistency checks in unit tests (sipa)
+- #7751 `84370d5` test_framework: python3.4 authproxy compat (laanwj)
+- #7744 `d8e862a` test_framework: detect failure of bitcoind startup (laanwj)
+- #8280 `115735d` Increase sync_blocks() timeouts in pruning.py (MarcoFalke)
+- #8340 `af9b7a9` Solve trivial merge conflict in p2p-segwit.py (MarcoFalke)
+- #8067 `3e4cf8f` Travis: use slim generic image, and some fixups (theuni)
+- #7951 `5c7df70` Test_framework: Properly print exception (MarcoFalke)
+- #8070 `7771aa5` Remove non-determinism which is breaking net_tests #8069 (EthanHeilman)
+- #8309 `bb2646a` Add wallet-hd test (MarcoFalke)
+- #8444 `cd0910b` Fix p2p-feefilter.py for changed tx relay behavior (sdaftuar)
+
+### Mining
+
+- #7507 `11c7699` Remove internal miner (Leviathn)
+- #7663 `c87f51e` Make the generate RPC call function for non-regtest (sipa)
+- #7671 `e2ebd25` Add generatetoaddress RPC to mine to an address (achow101)
+- #7935 `66ed450` Versionbits: GBT support (luke-jr)
+- #7600 `66db2d6` Select transactions using feerate-with-ancestors (sdaftuar)
+- #8295 `f5660d3` Mining-related fixups for 0.13.0 (sdaftuar)
+- #7796 `536b75e` Add support for negative fee rates, fixes `prioritizetransaction` (MarcoFalke)
+- #8362 `86edc20` Scale legacy sigop count in CreateNewBlock (sdaftuar)
+- #8489 `8b0eee6` Bugfix: Use pre-BIP141 sigops until segwit activates (GBT) (luke-jr)
+
+### Documentation and miscellaneous
+
+- #7423 `69e2a40` Add example for building with constrained resources (jarret)
+- #8254 `c2c69ed` Add OSX ZMQ requirement to QA readme (fanquake)
+- #8203 `377d131` Clarify documentation for running a tor node (nathaniel-mahieu)
+- #7428 `4b12266` Add example for listing ./configure flags (nathaniel-mahieu)
+- #7847 `3eae681` Add arch linux build example (mruddy)
+- #7968 `ff69aaf` Fedora build requirements (wtogami)
+- #8013 `fbedc09` Fedora build requirements, add gcc-c++ and fix typo (wtogami)
+- #8009 `fbd8478` Fixed invalid example paths in gitian-building.md (JeremyRand)
+- #8240 `63fbdbc` Mention Windows XP end of support in release notes (laanwj)
+- #8303 `5077d2c` Update bips.md for CSV softfork (fanquake)
+- #7789 `e0b3e19` Add note about using the Qt official binary installer (paveljanik)
+- #7791 `e30a5b0` Change Precise to Trusty in gitian-building.md (JeremyRand)
+- #7838 `8bb5d3d` Update gitian build guide to debian 8.4.0 (fanquake)
+- #7855 `b778e59` Replace precise with trusty (MarcoFalke)
+- #7975 `fc23fee` Update bitcoin-core GitHub links (MarcoFalke)
+- #8034 `e3a8207` Add basic git squash workflow (fanquake)
+- #7813 `214ec0b` Update port in tor.md (MarcoFalke)
+- #8193 `37c9830` Use Debian 8.5 in the gitian-build guide (fanquake)
+- #8261 `3685e0c` Clarify help for `getblockchaininfo` (paveljanik)
+- #7185 `ea0f5a2` Note that reviewers should mention the id of the commits they reviewed (pstratem)
+- #7290 `c851d8d` [init] Add missing help for args (MarcoFalke)
+- #7281 `f9fd4c2` Improve CheckInputs() comment about sig verification (petertodd)
+- #7417 `1e06bab` Minor improvements to the release process (PRabahy)
+- #7444 `4cdbd42` Improve block validity/ConnectBlock() comments (petertodd)
+- #7527 `db2e1c0` Fix and cleanup listreceivedbyX documentation (instagibbs)
+- #7541 `b6e00af` Clarify description of blockindex (pinheadmz)
+- #7590 `f06af57` Improving wording related to Boost library requirements [updated] (jonathancross)
+- #7635 `0fa88ef` Add dependency info to test docs (elliotolds)
+- #7609 `3ba07bd` RPM spec file project (AliceWonderMiscreations)
+- #7850 `229a17c` Removed call to `TryCreateDirectory` from `GetDefaultDataDir` in `src/util.cpp` (alexreg)
+- #7888 `ec870e1` Prevector: fix 2 bugs in currently unreached code paths (kazcw)
+- #7922 `90653bc` CBase58Data::SetString: cleanse the full vector (kazcw)
+- #7881 `c4e8390` Update release process (laanwj)
+- #7952 `a9c8b74` Log invalid block hash to make debugging easier (paveljanik)
+- #7974 `8206835` More comments on the design of AttemptToEvictConnection (gmaxwell)
+- #7795 `47a7cfb` UpdateTip: log only one line at most per block (laanwj)
+- #8110 `e7e25ea` Add benchmarking notes (fanquake)
+- #8121 `58f0c92` Update implemented BIPs list (fanquake)
+- #8029 `58725ba` Simplify OS X build notes (fanquake)
+- #8143 `d46b8b5` comment nit: miners don't vote (instagibbs)
+- #8136 `22e0b35` Log/report in 10% steps during VerifyDB (jonasschnelli)
+- #8168 `d366185` util: Add ParseUInt32 and ParseUInt64 (laanwj)
+- #8178 `f7b1bfc` Add git and github tips and tricks to developer notes (sipa)
+- #8177 `67db011` developer notes: updates for C++11 (kazcw)
+- #8229 `8ccdac1` [Doc] Update OS X build notes for 10.11 SDK (fanquake)
+- #8233 `9f1807a` Mention Linux ARM executables in release process and notes (laanwj)
+- #7540 `ff46dd4` Rename OP_NOP3 to OP_CHECKSEQUENCEVERIFY (btcdrak)
+- #8289 `26316ff` bash-completion: Adapt for 0.12 and 0.13 (roques)
+- #7453 `3dc3149` Missing patches from 0.12 (MarcoFalke)
+- #7113 `54a550b` Switch to a more efficient rolling Bloom filter (sipa)
+- #7257 `de9e5ea` Combine common error strings for different options so translations can be shared and reused (luke-jr)
+- #7304 `b8f485c` [contrib] Add clang-format-diff.py (MarcoFalke)
+- #7378 `e6f97ef` devtools: replace github-merge with python version (laanwj)
+- #7395 `0893705` devtools: show pull and commit information in github-merge (laanwj)
+- #7402 `6a5932b` devtools: github-merge get toplevel dir without extra whitespace (achow101)
+- #7425 `20a408c` devtools: Fix utf-8 support in messages for github-merge (laanwj)
+- #7632 `409f843` Delete outdated test-patches reference (Lewuathe)
+- #7662 `386f438` remove unused NOBLKS_VERSION_{START,END} constants (rat4)
+- #7737 `aa0d2b2` devtools: make github-merge.py use py3 (laanwj)
+- #7781 `55db5f0` devtools: Auto-set branch to merge to in github-merge (laanwj)
+- #7934 `f17032f` Improve rolling bloom filter performance and benchmark (sipa)
+- #8004 `2efe38b` signal handling: fReopenDebugLog and fRequestShutdown should be type sig_atomic_t (catilac)
+- #7713 `f6598df` Fixes for verify-commits script (petertodd)
+- #8412 `8360d5b` libconsensus: Expose a flag for BIP112 (jtimon)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- 21E14
+- accraze
+- Adam Brown
+- Alexander Regueiro
+- Alex Morcos
+- Alfie John
+- Alice Wonder
+- AlSzacrel
+- Andrew Chow
+- Andrés G. Aragoneses
+- Bob McElrath
+- BtcDrak
+- calebogden
+- Cédric Félizard
+- Chirag Davé
+- Chris Moore
+- Chris Stewart
+- Christian von Roques
+- Chris Wheeler
+- Cory Fields
+- crowning-
+- Daniel Cousens
+- Daniel Kraft
+- Denis Lukianov
+- Elias Rohrer
+- Elliot Olds
+- Eric Shaw
+- error10
+- Ethan Heilman
+- face
+- fanquake
+- Francesco 'makevoid' Canessa
+- fsb4000
+- Gavin Andresen
+- gladoscc
+- Gregory Maxwell
+- Gregory Sanders
+- instagibbs
+- James O'Beirne
+- Jannes Faber
+- Jarret Dyrbye
+- Jeremy Rand
+- jloughry
+- jmacwhyte
+- Joao Fonseca
+- Johnson Lau
+- Jonas Nick
+- Jonas Schnelli
+- Jonathan Cross
+- João Barbosa
+- Jorge Timón
+- Kaz Wesley
+- Kefkius
+- kirkalx
+- Krzysztof Jurewicz
+- Leviathn
+- lewuathe
+- Luke Dashjr
+- Luv Khemani
+- Marcel Krüger
+- Marco Falke
+- Mark Friedenbach
+- Matt
+- Matt Bogosian
+- Matt Corallo
+- Matthew English
+- Matthew Zipkin
+- mb300sd
+- Mitchell Cash
+- mrbandrews
+- mruddy
+- Murch
+- Mustafa
+- Nathaniel Mahieu
+- Nicolas Dorier
+- Patrick Strateman
+- Paul Rabahy
+- paveljanik
+- Pavel Janík
+- Pavel Vasin
+- Pedro Branco
+- Peter Todd
+- Philip Kaufmann
+- Pieter Wuille
+- Prayag Verma
+- ptschip
+- Puru
+- randy-waterhouse
+- R E Broadley
+- Rusty Russell
+- Suhas Daftuar
+- Suriyaa Kudo
+- TheLazieR Yip
+- Thomas Kerin
+- Tom Harding
+- Tyler Hardin
+- UdjinM6
+- Warren Togami
+- Will Binns
+- Wladimir J. van der Laan
+- Yuri Zhykin
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
diff --git a/doc/release-notes/release-notes-0.13.1.md b/doc/release-notes/release-notes-0.13.1.md
new file mode 100644
index 0000000000..75c2d61be8
--- /dev/null
+++ b/doc/release-notes/release-notes-0.13.1.md
@@ -0,0 +1,410 @@
+Bitcoin Core version 0.13.1 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.13.1/>
+
+This is a new minor version release, including activation parameters for the
+segwit softfork, various bugfixes and performance improvements, as well as
+updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+Compatibility
+==============
+
+Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support),
+an OS initially released in 2001. This means that not even critical security
+updates will be released anymore. Without security updates, using a bitcoin
+wallet on a XP machine is irresponsible at least.
+
+In addition to that, with 0.12.x there have been varied reports of Bitcoin Core
+randomly crashing on Windows XP. It is [not clear](https://github.com/bitcoin/bitcoin/issues/7681#issuecomment-217439891)
+what the source of these crashes is, but it is likely that upstream
+libraries such as Qt are no longer being tested on XP.
+
+We do not have time nor resources to provide support for an OS that is
+end-of-life. From 0.13.0 on, Windows XP is no longer supported. Users are
+suggested to upgrade to a newer version of Windows, or install an alternative OS
+that is supported.
+
+No attempt is made to prevent installing or running the software on Windows XP,
+you can still do so at your own risk, but do not expect it to work: do not
+report issues about Windows XP to the issue tracker.
+
+From 0.13.1 onwards OS X 10.7 is no longer supported. 0.13.0 was intended to work on 10.7+,
+but severe issues with the libc++ version on 10.7.x keep it from running reliably.
+0.13.1 now requires 10.8+, and will communicate that to 10.7 users, rather than crashing unexpectedly.
+
+Notable changes
+===============
+
+Segregated witness soft fork
+----------------------------
+
+Segregated witness (segwit) is a soft fork that, if activated, will
+allow transaction-producing software to separate (segregate) transaction
+signatures (witnesses) from the part of the data in a transaction that is
+covered by the txid. This provides several immediate benefits:
+
+- **Elimination of unwanted transaction malleability:** Segregating the witness
+ allows both existing and upgraded software to calculate the transaction
+ identifier (txid) of transactions without referencing the witness, which can
+ sometimes be changed by third-parties (such as miners) or by co-signers in a
+ multisig spend. This solves all known cases of unwanted transaction
+ malleability, which is a problem that makes programming Bitcoin wallet
+ software more difficult and which seriously complicates the design of smart
+ contracts for Bitcoin.
+
+- **Capacity increase:** Segwit transactions contain new fields that are not
+ part of the data currently used to calculate the size of a block, which
+ allows a block containing segwit transactions to hold more data than allowed
+ by the current maximum block size. Estimates based on the transactions
+ currently found in blocks indicate that if all wallets switch to using
+ segwit, the network will be able to support about 70% more transactions. The
+ network will also be able to support more of the advanced-style payments
+ (such as multisig) than it can support now because of the different weighting
+ given to different parts of a transaction after segwit activates (see the
+ following section for details).
+
+- **Weighting data based on how it affects node performance:** Some parts of
+ each Bitcoin block need to be stored by nodes in order to validate future
+ blocks; other parts of a block can be immediately forgotten (pruned) or used
+ only for helping other nodes sync their copy of the block chain. One large
+ part of the immediately prunable data are transaction signatures (witnesses),
+ and segwit makes it possible to give a different "weight" to segregated
+ witnesses to correspond with the lower demands they place on node resources.
+ Specifically, each byte of a segregated witness is given a weight of 1, each
+ other byte in a block is given a weight of 4, and the maximum allowed weight
+ of a block is 4 million. Weighting the data this way better aligns the most
+ profitable strategy for creating blocks with the long-term costs of block
+ validation.
+
+- **Signature covers value:** A simple improvement in the way signatures are
+ generated in segwit simplifies the design of secure signature generators
+ (such as hardware wallets), reduces the amount of data the signature
+ generator needs to download, and allows the signature generator to operate
+ more quickly. This is made possible by having the generator sign the amount
+ of bitcoins they think they are spending, and by having full nodes refuse to
+ accept those signatures unless the amount of bitcoins being spent is exactly
+ the same as was signed. For non-segwit transactions, wallets instead had to
+ download the complete previous transactions being spent for every payment
+ they made, which could be a slow operation on hardware wallets and in other
+ situations where bandwidth or computation speed was constrained.
+
+- **Linear scaling of sighash operations:** In 2015 a block was produced that
+ required about 25 seconds to validate on modern hardware because of the way
+ transaction signature hashes are performed. Other similar blocks, or blocks
+ that could take even longer to validate, can still be produced today. The
+ problem that caused this can't be fixed in a soft fork without unwanted
+ side-effects, but transactions that opt-in to using segwit will now use a
+ different signature method that doesn't suffer from this problem and doesn't
+ have any unwanted side-effects.
+
+- **Increased security for multisig:** Bitcoin addresses (both P2PKH addresses
+ that start with a '1' and P2SH addresses that start with a '3') use a hash
+ function known as RIPEMD-160. For P2PKH addresses, this provides about 160
+ bits of security---which is beyond what cryptographers believe can be broken
+ today. But because P2SH is more flexible, only about 80 bits of security is
+ provided per address. Although 80 bits is very strong security, it is within
+ the realm of possibility that it can be broken by a powerful adversary.
+ Segwit allows advanced transactions to use the SHA256 hash function instead,
+ which provides about 128 bits of security (that is 281 trillion times as
+ much security as 80 bits and is equivalent to the maximum bits of security
+ believed to be provided by Bitcoin's choice of parameters for its Elliptic
+ Curve Digital Security Algorithm [ECDSA].)
+
+- **More efficient almost-full-node security** Satoshi Nakamoto's original
+ Bitcoin paper describes a method for allowing newly-started full nodes to
+ skip downloading and validating some data from historic blocks that are
+ protected by large amounts of proof of work. Unfortunately, Nakamoto's
+ method can't guarantee that a newly-started node using this method will
+ produce an accurate copy of Bitcoin's current ledger (called the UTXO set),
+ making the node vulnerable to falling out of consensus with other nodes.
+ Although the problems with Nakamoto's method can't be fixed in a soft fork,
+ Segwit accomplishes something similar to his original proposal: it makes it
+ possible for a node to optionally skip downloading some blockchain data
+ (specifically, the segregated witnesses) while still ensuring that the node
+ can build an accurate copy of the UTXO set for the block chain with the most
+ proof of work. Segwit enables this capability at the consensus layer, but
+ note that Bitcoin Core does not provide an option to use this capability as
+ of this 0.13.1 release.
+
+- **Script versioning:** Segwit makes it easy for future soft forks to allow
+ Bitcoin users to individually opt-in to almost any change in the Bitcoin
+ Script language when those users receive new transactions. Features
+ currently being researched by Bitcoin Core contributors that may use this
+ capability include support for Schnorr signatures, which can improve the
+ privacy and efficiency of multisig transactions (or transactions with
+ multiple inputs), and Merklized Abstract Syntax Trees (MAST), which can
+ improve the privacy and efficiency of scripts with two or more conditions.
+ Other Bitcoin community members are studying several other improvements
+ that can be made using script versioning.
+
+Activation for the segwit soft fork is being managed using BIP9
+versionbits. Segwit's version bit is bit 1, and nodes will begin
+tracking which blocks signal support for segwit at the beginning of the
+first retarget period after segwit's start date of 15 November 2016. If
+95% of blocks within a 2,016-block retarget period (about two weeks)
+signal support for segwit, the soft fork will be locked in. After
+another 2,016 blocks, segwit will activate.
+
+For more information about segwit, please see the [segwit FAQ][], the
+[segwit wallet developers guide][] or BIPs [141][BIP141], [143][BIP143],
+[144][BIP144], and [145][BIP145]. If you're a miner or mining pool
+operator, please see the [versionbits FAQ][] for information about
+signaling support for a soft fork.
+
+[Segwit FAQ]: https://bitcoincore.org/en/2016/01/26/segwit-benefits/
+[segwit wallet developers guide]: https://bitcoincore.org/en/segwit_wallet_dev/
+[BIP141]: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
+[BIP143]: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
+[BIP144]: https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki
+[BIP145]: https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki
+[versionbits FAQ]: https://bitcoincore.org/en/2016/06/08/version-bits-miners-faq/
+
+
+Null dummy soft fork
+-------------------
+
+Combined with the segwit soft fork is an additional change that turns a
+long-existing network relay policy into a consensus rule. The
+`OP_CHECKMULTISIG` and `OP_CHECKMULTISIGVERIFY` opcodes consume an extra
+stack element ("dummy element") after signature validation. The dummy
+element is not inspected in any manner, and could be replaced by any
+value without invalidating the script.
+
+Because any value can be used for this dummy element, it's possible for
+a third-party to insert data into other people's transactions, changing
+the transaction's txid (called transaction malleability) and possibly
+causing other problems.
+
+Since Bitcoin Core 0.10.0, nodes have defaulted to only relaying and
+mining transactions whose dummy element was a null value (0x00, also
+called OP_0). The null dummy soft fork turns this relay rule into a
+consensus rule both for non-segwit transactions and segwit transactions,
+so that this method of mutating transactions is permanently eliminated
+from the network.
+
+Signaling for the null dummy soft fork is done by signaling support
+for segwit, and the null dummy soft fork will activate at the same time
+as segwit.
+
+For more information, please see [BIP147][].
+
+[BIP147]: https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki
+
+Low-level RPC changes
+---------------------
+
+- `importprunedfunds` only accepts two required arguments. Some versions accept
+ an optional third arg, which was always ignored. Make sure to never pass more
+ than two arguments.
+
+
+Linux ARM builds
+----------------
+
+With the 0.13.0 release, pre-built Linux ARM binaries were added to the set of
+uploaded executables. Additional detail on the ARM architecture targeted by each
+is provided below.
+
+The following extra files can be found in the download directory or torrent:
+
+- `bitcoin-${VERSION}-arm-linux-gnueabihf.tar.gz`: Linux binaries targeting
+ the 32-bit ARMv7-A architecture.
+- `bitcoin-${VERSION}-aarch64-linux-gnu.tar.gz`: Linux binaries targeting
+ the 64-bit ARMv8-A architecture.
+
+ARM builds are still experimental. If you have problems on a certain device or
+Linux distribution combination please report them on the bug tracker, it may be
+possible to resolve them. Note that the device you use must be (backward)
+compatible with the architecture targeted by the binary that you use.
+For example, a Raspberry Pi 2 Model B or Raspberry Pi 3 Model B (in its 32-bit
+execution state) device, can run the 32-bit ARMv7-A targeted binary. However,
+no model of Raspberry Pi 1 device can run either binary because they are all
+ARMv6 architecture devices that are not compatible with ARMv7-A or ARMv8-A.
+
+Note that Android is not considered ARM Linux in this context. The executables
+are not expected to work out of the box on Android.
+
+
+0.13.1 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, refactors and string updates. For convenience in locating
+the code changes and accompanying discussion, both the pull request and
+git merge commit are mentioned.
+
+### Consensus
+- #8636 `9dfa0c8` Implement NULLDUMMY softfork (BIP147) (jl2012)
+- #8848 `7a34a46` Add NULLDUMMY verify flag in bitcoinconsensus.h (jl2012)
+- #8937 `8b66659` Define start and end time for segwit deployment (sipa)
+
+### RPC and other APIs
+- #8581 `526d2b0` Drop misleading option in importprunedfunds (MarcoFalke)
+- #8699 `a5ec248` Remove createwitnessaddress RPC command (jl2012)
+- #8780 `794b007` Deprecate getinfo (MarcoFalke)
+- #8832 `83ad563` Throw JSONRPCError when utxo set can not be read (MarcoFalke)
+- #8884 `b987348` getblockchaininfo help: pruneheight is the lowest, not highest, block (luke-jr)
+- #8858 `3f508ed` rpc: Generate auth cookie in hex instead of base64 (laanwj)
+- #8951 `7c2bf4b` RPC/Mining: getblocktemplate: Update and fix formatting of help (luke-jr)
+
+### Block and transaction handling
+- #8611 `a9429ca` Reduce default number of blocks to check at startup (sipa)
+- #8634 `3e80ab7` Add policy: null signature for failed CHECK(MULTI)SIG (jl2012)
+- #8525 `1672225` Do not store witness txn in rejection cache (sipa)
+- #8499 `9777fe1` Add several policy limits and disable uncompressed keys for segwit scripts (jl2012)
+- #8526 `0027672` Make non-minimal OP_IF/NOTIF argument non-standard for P2WSH (jl2012)
+- #8524 `b8c79a0` Precompute sighashes (sipa)
+- #8651 `b8c79a0` Predeclare PrecomputedTransactionData as struct (sipa)
+
+### P2P protocol and network code
+- #8740 `42ea51a` No longer send local address in addrMe (laanwj)
+- #8427 `69d1cd2` Ignore `notfound` P2P messages (laanwj)
+- #8573 `4f84082` Set jonasschnellis dns-seeder filter flag (jonasschnelli)
+- #8712 `23feab1` Remove maxuploadtargets recommended minimum (jonasschnelli)
+- #8862 `7ae6242` Fix a few cases where messages were sent after requested disconnect (theuni)
+- #8393 `fe1975a` Support for compact blocks together with segwit (sipa)
+- #8282 `2611ad7` Feeler connections to increase online addrs in the tried table (EthanHeilman)
+- #8612 `2215c22` Check for compatibility with download in FindNextBlocksToDownload (sipa)
+- #8606 `bbf379b` Fix some locks (sipa)
+- #8594 `ab295bb` Do not add random inbound peers to addrman (gmaxwell)
+- #8940 `5b4192b` Add x9 service bit support to dnsseed.bluematt.me, seed.bitcoinstats.com (TheBlueMatt, cdecker)
+- #8944 `685e4c7` Remove bogus assert on number of oubound connections. (TheBlueMatt)
+- #8949 `0dbc48a` Be more agressive in getting connections to peers with relevant services (gmaxwell)
+
+### Build system
+- #8293 `fa5b249` Allow building libbitcoinconsensus without any univalue (luke-jr)
+- #8492 `8b0bdd3` Allow building bench_bitcoin by itself (luke-jr)
+- #8563 `147003c` Add configure check for -latomic (ajtowns)
+- #8626 `ea51b0f` Berkeley DB v6 compatibility fix (netsafe)
+- #8520 `75f2065` Remove check for `openssl/ec.h` (laanwj)
+
+### GUI
+- #8481 `d9f0d4e` Fix minimize and close bugs (adlawren)
+- #8487 `a37cec5` Persist the datadir after option reset (achow101)
+- #8697 `41fd852` Fix op order to append first alert (rodasmith)
+- #8678 `8e03382` Fix UI bug that could result in paying unexpected fee (jonasschnelli)
+- #8911 `7634d8e` Translate all files, even if wallet disabled (laanwj)
+- #8540 `1db3352` Fix random segfault when closing "Choose data directory" dialog (laanwj)
+- #7579 `f1c0d78` Show network/chain errors in the GUI (jonasschnelli)
+
+### Wallet
+- #8443 `464dedd` Trivial cleanup of HD wallet changes (jonasschnelli)
+- #8539 `cb07f19` CDB: fix debug output (crowning-)
+- #8664 `091cdeb` Fix segwit-related wallet bug (sdaftuar)
+- #8693 `c6a6291` Add witness address to address book (instagibbs)
+- #8765 `6288659` Remove "unused" ThreadFlushWalletDB from removeprunedfunds (jonasschnelli)
+
+### Tests and QA
+- #8713 `ae8c7df` create_cache: Delete temp dir when done (MarcoFalke)
+- #8716 `e34374e` Check legacy wallet as well (MarcoFalke)
+- #8750 `d6ebe13` Refactor RPCTestHandler to prevent TimeoutExpired (MarcoFalke)
+- #8652 `63462c2` remove root test directory for RPC tests (yurizhykin)
+- #8724 `da94272` walletbackup: Sync blocks inside the loop (MarcoFalke)
+- #8400 `bea02dc` enable rpcbind_test (yurizhykin)
+- #8417 `f70be14` Add walletdump RPC test (including HD- & encryption-tests) (jonasschnelli)
+- #8419 `a7aa3cc` Enable size accounting in mining unit tests (sdaftuar)
+- #8442 `8bb1efd` Rework hd wallet dump test (MarcoFalke)
+- #8528 `3606b6b` Update p2p-segwit.py to reflect correct behavior (instagibbs)
+- #8531 `a27cdd8` abandonconflict: Use assert_equal (MarcoFalke)
+- #8667 `6b07362` Fix SIGHASH_SINGLE bug in test_framework SignatureHash (jl2012)
+- #8673 `03b0196` Fix obvious assignment/equality error in test (JeremyRubin)
+- #8739 `cef633c` Fix broken sendcmpct test in p2p-compactblocks.py (sdaftuar)
+- #8418 `ff893aa` Add tests for compact blocks (sdaftuar)
+- #8803 `375437c` Ping regularly in p2p-segwit.py to keep connection alive (jl2012)
+- #8827 `9bbe66e` Split up slow RPC calls to avoid pruning test timeouts (sdaftuar)
+- #8829 `2a8bca4` Add bitcoin-tx JSON tests (jnewbery)
+- #8834 `1dd1783` blockstore: Switch to dumb dbm (MarcoFalke)
+- #8835 `d87227d` nulldummy.py: Don't run unused code (MarcoFalke)
+- #8836 `eb18cc1` bitcoin-util-test.py should fail if the output file is empty (jnewbery)
+- #8839 `31ab2f8` Avoid ConnectionResetErrors during RPC tests (laanwj)
+- #8840 `cbc3fe5` Explicitly set encoding to utf8 when opening text files (laanwj)
+- #8841 `3e4abb5` Fix nulldummy test (jl2012)
+- #8854 `624a007` Fix race condition in p2p-compactblocks test (sdaftuar)
+- #8857 `1f60d45` mininode: Only allow named args in wait_until (MarcoFalke)
+- #8860 `0bee740` util: Move wait_bitcoinds() into stop_nodes() (MarcoFalke)
+- #8882 `b73f065` Fix race conditions in p2p-compactblocks.py and sendheaders.py (sdaftuar)
+- #8904 `cc6f551` Fix compact block shortids for a test case (dagurval)
+
+### Documentation
+- #8754 `0e2c6bd` Target protobuf 2.6 in OS X build notes. (fanquake)
+- #8461 `b17a3f9` Document return value of networkhashps for getmininginfo RPC endpoint (jlopp)
+- #8512 `156e305` Corrected JSON typo on setban of net.cpp (sevastos)
+- #8683 `8a7d7ff` Fix incorrect file name bitcoin.qrc (bitcoinsSG)
+- #8891 `5e0dd9e` Update bips.md for Segregated Witness (fanquake)
+- #8545 `863ae74` Update git-subtree-check.sh README (MarcoFalke)
+- #8607 `486650a` Fix doxygen off-by-one comments, fix typos (MarcoFalke)
+- #8560 `c493f43` Fix two VarInt examples in serialize.h (cbarcenas)
+- #8737 `084cae9` UndoReadFromDisk works on undo files (rev), not on block files (paveljanik)
+- #8625 `0a35573` Clarify statement about parallel jobs in rpc-tests.py (isle2983)
+- #8624 `0e6d753` build: Mention curl (MarcoFalke)
+- #8604 `b09e13c` build,doc: Update for 0.13.0+ and OpenBSD 5.9 (laanwj)
+- #8939 `06d15fb` Update implemented bips for 0.13.1 (sipa)
+
+### Miscellaneous
+- #8742 `d31ac72` Specify Protobuf version 2 in paymentrequest.proto (fanquake)
+- #8414,#8558,#8676,#8700,#8701,#8702 Add missing copyright headers (isle2983, kazcw)
+- #8899 `4ed2627` Fix wake from sleep issue with Boost 1.59.0 (fanquake)
+- #8817 `bcf3806` update bitcoin-tx to output witness data (jnewbery)
+- #8513 `4e5fc31` Fix a type error that would not compile on OSX. (JeremyRubin)
+- #8392 `30eac2d` Fix several node initialization issues (sipa)
+- #8548 `305d8ac` Use `__func__` to get function name for output printing (MarcoFalke)
+- #8291 `a987431` [util] CopyrightHolders: Check for untranslated substitution (MarcoFalke)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- adlawren
+- Alexey Vesnin
+- Anders Øyvind Urke-Sætre
+- Andrew Chow
+- Anthony Towns
+- BtcDrak
+- Chris Stewart
+- Christian Barcenas
+- Christian Decker
+- Cory Fields
+- crowning-
+- Dagur Valberg Johannsson
+- David A. Harding
+- Eric Lombrozo
+- Ethan Heilman
+- fanquake
+- Gaurav Rana
+- Gregory Maxwell
+- instagibbs
+- isle2983
+- Jameson Lopp
+- Jeremy Rubin
+- jnewbery
+- Johnson Lau
+- Jonas Schnelli
+- jonnynewbs
+- Justin Camarena
+- Kaz Wesley
+- leijurv
+- Luke Dashjr
+- MarcoFalke
+- Marty Jones
+- Matt Corallo
+- Micha
+- Michael Ford
+- mruddy
+- Pavel Janík
+- Pieter Wuille
+- rodasmith
+- Sev
+- Suhas Daftuar
+- whythat
+- Wladimir J. van der Laan
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
diff --git a/doc/release-notes/release-notes-0.13.2.md b/doc/release-notes/release-notes-0.13.2.md
new file mode 100644
index 0000000000..45fff5c8bb
--- /dev/null
+++ b/doc/release-notes/release-notes-0.13.2.md
@@ -0,0 +1,178 @@
+Bitcoin Core version 0.13.2 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.13.2/>
+
+This is a new minor version release, including various bugfixes and
+performance improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+Compatibility
+==============
+
+Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support),
+an OS initially released in 2001. This means that not even critical security
+updates will be released anymore. Without security updates, using a bitcoin
+wallet on a XP machine is irresponsible at least.
+
+In addition to that, with 0.12.x there have been varied reports of Bitcoin Core
+randomly crashing on Windows XP. It is [not clear](https://github.com/bitcoin/bitcoin/issues/7681#issuecomment-217439891)
+what the source of these crashes is, but it is likely that upstream
+libraries such as Qt are no longer being tested on XP.
+
+We do not have time nor resources to provide support for an OS that is
+end-of-life. From 0.13.0 on, Windows XP is no longer supported. Users are
+suggested to upgrade to a newer version of Windows, or install an alternative OS
+that is supported.
+
+No attempt is made to prevent installing or running the software on Windows XP,
+you can still do so at your own risk, but do not expect it to work: do not
+report issues about Windows XP to the issue tracker.
+
+From 0.13.1 onwards OS X 10.7 is no longer supported. 0.13.0 was intended to work on 10.7+,
+but severe issues with the libc++ version on 10.7.x keep it from running reliably.
+0.13.1 now requires 10.8+, and will communicate that to 10.7 users, rather than crashing unexpectedly.
+
+Notable changes
+===============
+
+Change to wallet handling of mempool rejection
+-----------------------------------------------
+
+When a newly created transaction failed to enter the mempool due to
+the limits on chains of unconfirmed transactions the sending RPC
+calls would return an error. The transaction would still be queued
+in the wallet and, once some of the parent transactions were
+confirmed, broadcast after the software was restarted.
+
+This behavior has been changed to return success and to reattempt
+mempool insertion at the same time transaction rebroadcast is
+attempted, avoiding a need for a restart.
+
+Transactions in the wallet which cannot be accepted into the mempool
+can be abandoned with the previously existing abandontransaction RPC
+(or in the GUI via a context menu on the transaction).
+
+
+0.13.2 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, refactors and string updates. For convenience in locating
+the code changes and accompanying discussion, both the pull request and
+git merge commit are mentioned.
+
+### Consensus
+- #9293 `e591c10` [0.13 Backport #9053] IBD using chainwork instead of height and not using header timestamp (gmaxwell)
+- #9053 `5b93eee` IBD using chainwork instead of height and not using header timestamps (gmaxwell)
+
+### RPC and other APIs
+- #8845 `1d048b9` Don't return the address of a P2SH of a P2SH (jnewbery)
+- #9041 `87fbced` keypoololdest denote Unix epoch, not GMT (s-matthew-english)
+- #9122 `f82c81b` fix getnettotals RPC description about timemillis (visvirial)
+- #9042 `5bcb05d` [rpc] ParseHash: Fail when length is not 64 (MarcoFalke)
+- #9194 `f26dab7` Add option to return non-segwit serialization via rpc (instagibbs)
+- #9347 `b711390` [0.13.2] wallet/rpc backports (MarcoFalke)
+- #9292 `c365556` Complain when unknown rpcserialversion is specified (sipa)
+- #9322 `49a612f` [qa] Don't set unknown rpcserialversion (MarcoFalke)
+
+### Block and transaction handling
+- #8357 `ce0d817` [mempool] Fix relaypriority calculation error (maiiz)
+- #9267 `0a4aa87` [0.13 backport #9239] Disable fee estimates for a confirm target of 1 block (morcos)
+- #9196 `0c09d9f` Send tip change notification from invalidateblock (ryanofsky)
+
+### P2P protocol and network code
+- #8995 `9ef3875` Add missing cs_main lock to ::GETBLOCKTXN processing (TheBlueMatt)
+- #9234 `94531b5` torcontrol: Explicitly request RSA1024 private key (laanwj)
+- #8637 `2cad5db` Compact Block Tweaks (rebase of #8235) (sipa)
+- #9058 `286e548` Fixes for p2p-compactblocks.py test timeouts on travis (#8842) (ryanofsky)
+- #8865 `4c71fc4` Decouple peer-processing-logic from block-connection-logic (TheBlueMatt)
+- #9117 `6fe3981` net: don't send feefilter messages before the version handshake is complete (theuni)
+- #9188 `ca1fd75` Make orphan parent fetching ask for witnesses (gmaxwell)
+- #9052 `3a3bcbf` Use RelevantServices instead of node_network in AttemptToEvict (gmaxwell)
+- #9048 `9460771` [0.13 backport #9026] Fix handling of invalid compact blocks (sdaftuar)
+- #9357 `03b6f62` [0.13 backport #9352] Attempt reconstruction from all compact block announcements (sdaftuar)
+- #9189 `b96a8f7` Always add default_witness_commitment with GBT client support (sipa)
+- #9253 `28d0f22` Fix calculation of number of bound sockets to use (TheBlueMatt)
+- #9199 `da5a16b` Always drop the least preferred HB peer when adding a new one (gmaxwell)
+
+### Build system
+- #9169 `d1b4da9` build: fix qt5.7 build under macOS (theuni)
+- #9326 `a0f7ece` Update for OpenSSL 1.1 API (gmaxwell)
+- #9224 `396c405` Prevent FD_SETSIZE error building on OpenBSD (ivdsangen)
+
+### GUI
+- #8972 `6f86b53` Make warnings label selectable (jonasschnelli) (MarcoFalke)
+- #9185 `6d70a73` Fix coincontrol sort issue (jonasschnelli)
+- #9094 `5f3a12c` Use correct conversion function for boost::path datadir (laanwj)
+- #8908 `4a974b2` Update bitcoin-qt.desktop (s-matthew-english)
+- #9190 `dc46b10` Plug many memory leaks (laanwj)
+
+### Wallet
+- #9290 `35174a0` Make RelayWalletTransaction attempt to AcceptToMemoryPool (gmaxwell)
+- #9295 `43bcfca` Bugfix: Fundrawtransaction: don't terminate when keypool is empty (jonasschnelli)
+- #9302 `f5d606e` Return txid even if ATMP fails for new transaction (sipa)
+- #9262 `fe39f26` Prefer coins that have fewer ancestors, sanity check txn before ATMP (instagibbs)
+
+### Tests and QA
+- #9159 `eca9b46` Wait for specific block announcement in p2p-compactblocks (ryanofsky)
+- #9186 `dccdc3a` Fix use-after-free in scheduler tests (laanwj)
+- #9168 `3107280` Add assert_raises_message to check specific error message (mrbandrews)
+- #9191 `29435db` 0.13.2 Backports (MarcoFalke)
+- #9077 `1d4c884` Increase wallet-dump RPC timeout (ryanofsky)
+- #9098 `ecd7db5` Handle zombies and cluttered tmpdirs (MarcoFalke)
+- #8927 `387ec9d` Add script tests for FindAndDelete in pre-segwit and segwit scripts (jl2012)
+- #9200 `eebc699` bench: Fix subtle counting issue when rescaling iteration count (laanwj)
+
+### Miscellaneous
+- #8838 `094848b` Calculate size and weight of block correctly in CreateNewBlock() (jnewbery)
+- #8920 `40169dc` Set minimum required Boost to 1.47.0 (fanquake)
+- #9251 `a710a43` Improvement of documentation of command line parameter 'whitelist' (wodry)
+- #8932 `106da69` Allow bitcoin-tx to create v2 transactions (btcdrak)
+- #8929 `12428b4` add software-properties-common (sigwo)
+- #9120 `08d1c90` bug: Missed one "return false" in recent refactoring in #9067 (UdjinM6)
+- #9067 `f85ee01` Fix exit codes (UdjinM6)
+- #9340 `fb987b3` [0.13] Update secp256k1 subtree (MarcoFalke)
+- #9229 `b172377` Remove calls to getaddrinfo_a (TheBlueMatt)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Alex Morcos
+- BtcDrak
+- Cory Fields
+- fanquake
+- Gregory Maxwell
+- Gregory Sanders
+- instagibbs
+- Ivo van der Sangen
+- jnewbery
+- Johnson Lau
+- Jonas Schnelli
+- Luke Dashjr
+- maiiz
+- MarcoFalke
+- Masahiko Hyuga
+- Matt Corallo
+- matthias
+- mrbandrews
+- Pavel Janík
+- Pieter Wuille
+- randy-waterhouse
+- Russell Yanofsky
+- S. Matthew English
+- Steven
+- Suhas Daftuar
+- UdjinM6
+- Wladimir J. van der Laan
+- wodry
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
diff --git a/doc/release-notes/release-notes-0.14.0.md b/doc/release-notes/release-notes-0.14.0.md
new file mode 100644
index 0000000000..c41f22979b
--- /dev/null
+++ b/doc/release-notes/release-notes-0.14.0.md
@@ -0,0 +1,873 @@
+Bitcoin Core version 0.14.0 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.14.0/>
+
+This is a new major version release, including new features, various bugfixes
+and performance improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+Compatibility
+==============
+
+Bitcoin Core is extensively tested on multiple operating systems using
+the Linux kernel, macOS 10.8+, and Windows Vista and later.
+
+Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support),
+No attempt is made to prevent installing or running the software on Windows XP, you
+can still do so at your own risk but be aware that there are known instabilities and issues.
+Please do not report issues about Windows XP to the issue tracker.
+
+Bitcoin Core should also work on most other Unix-like systems but is not
+frequently tested on them.
+
+Notable changes
+===============
+
+Performance Improvements
+--------------
+
+Validation speed and network propagation performance have been greatly
+improved, leading to much shorter sync and initial block download times.
+
+- The script signature cache has been reimplemented as a "cuckoo cache",
+ allowing for more signatures to be cached and faster lookups.
+- Assumed-valid blocks have been introduced which allows script validation to
+ be skipped for ancestors of known-good blocks, without changing the security
+ model. See below for more details.
+- In some cases, compact blocks are now relayed before being fully validated as
+ per BIP152.
+- P2P networking has been refactored with a focus on concurrency and
+ throughput. Network operations are no longer bottlenecked by validation. As a
+ result, block fetching is several times faster than previous releases in many
+ cases.
+- The UTXO cache now claims unused mempool memory. This speeds up initial block
+ download as UTXO lookups are a major bottleneck there, and there is no use for
+ the mempool at that stage.
+
+
+Manual Pruning
+--------------
+
+Bitcoin Core has supported automatically pruning the blockchain since 0.11. Pruning
+the blockchain allows for significant storage space savings as the vast majority of
+the downloaded data can be discarded after processing so very little of it remains
+on the disk.
+
+Manual block pruning can now be enabled by setting `-prune=1`. Once that is set,
+the RPC command `pruneblockchain` can be used to prune the blockchain up to the
+specified height or timestamp.
+
+`getinfo` Deprecated
+--------------------
+
+The `getinfo` RPC command has been deprecated. Each field in the RPC call
+has been moved to another command's output with that command also giving
+additional information that `getinfo` did not provide. The following table
+shows where each field has been moved to:
+
+|`getinfo` field | Moved to |
+|------------------|-------------------------------------------|
+`"version"` | `getnetworkinfo()["version"]`
+`"protocolversion"`| `getnetworkinfo()["protocolversion"]`
+`"walletversion"` | `getwalletinfo()["walletversion"]`
+`"balance"` | `getwalletinfo()["balance"]`
+`"blocks"` | `getblockchaininfo()["blocks"]`
+`"timeoffset"` | `getnetworkinfo()["timeoffset"]`
+`"connections"` | `getnetworkinfo()["connections"]`
+`"proxy"` | `getnetworkinfo()["networks"][0]["proxy"]`
+`"difficulty"` | `getblockchaininfo()["difficulty"]`
+`"testnet"` | `getblockchaininfo()["chain"] == "test"`
+`"keypoololdest"` | `getwalletinfo()["keypoololdest"]`
+`"keypoolsize"` | `getwalletinfo()["keypoolsize"]`
+`"unlocked_until"` | `getwalletinfo()["unlocked_until"]`
+`"paytxfee"` | `getwalletinfo()["paytxfee"]`
+`"relayfee"` | `getnetworkinfo()["relayfee"]`
+`"errors"` | `getnetworkinfo()["warnings"]`
+
+ZMQ On Windows
+--------------
+
+Previously the ZeroMQ notification system was unavailable on Windows
+due to various issues with ZMQ. These have been fixed upstream and
+now ZMQ can be used on Windows. Please see [this document](https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md) for
+help with using ZMQ in general.
+
+Nested RPC Commands in Debug Console
+------------------------------------
+
+The ability to nest RPC commands has been added to the debug console. This
+allows users to have the output of a command become the input to another
+command without running the commands separately.
+
+The nested RPC commands use bracket syntax (i.e. `getwalletinfo()`) and can
+be nested (i.e. `getblock(getblockhash(1))`). Simple queries can be
+done with square brackets where object values are accessed with either an
+array index or a non-quoted string (i.e. `listunspent()[0][txid]`). Both
+commas and spaces can be used to separate parameters in both the bracket syntax
+and normal RPC command syntax.
+
+Network Activity Toggle
+-----------------------
+
+A RPC command and GUI toggle have been added to enable or disable all p2p
+network activity. The network status icon in the bottom right hand corner
+is now the GUI toggle. Clicking the icon will either enable or disable all
+p2p network activity. If network activity is disabled, the icon will
+be grayed out with an X on top of it.
+
+Additionally the `setnetworkactive` RPC command has been added which does
+the same thing as the GUI icon. The command takes one boolean parameter,
+`true` enables networking and `false` disables it.
+
+Out-of-sync Modal Info Layer
+----------------------------
+
+When Bitcoin Core is out-of-sync on startup, a semi-transparent information
+layer will be shown over top of the normal display. This layer contains
+details about the current sync progress and estimates the amount of time
+remaining to finish syncing. This layer can also be hidden and subsequently
+unhidden by clicking on the progress bar at the bottom of the window.
+
+Support for JSON-RPC Named Arguments
+------------------------------------
+
+Commands sent over the JSON-RPC interface and through the `bitcoin-cli` binary
+can now use named arguments. This follows the [JSON-RPC specification](http://www.jsonrpc.org/specification)
+for passing parameters by-name with an object.
+
+`bitcoin-cli` has been updated to support this by parsing `name=value` arguments
+when the `-named` option is given.
+
+Some examples:
+
+ src/bitcoin-cli -named help command="help"
+ src/bitcoin-cli -named getblockhash height=0
+ src/bitcoin-cli -named getblock blockhash=000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
+ src/bitcoin-cli -named sendtoaddress address="(snip)" amount="1.0" subtractfeefromamount=true
+
+The order of arguments doesn't matter in this case. Named arguments are also
+useful to leave out arguments that should stay at their default value. The
+rarely-used arguments `comment` and `comment_to` to `sendtoaddress`, for example, can
+be left out. However, this is not yet implemented for many RPC calls, this is
+expected to land in a later release.
+
+The RPC server remains fully backwards compatible with positional arguments.
+
+Opt into RBF When Sending
+-------------------------
+
+A new startup option, `-walletrbf`, has been added to allow users to have all
+transactions sent opt into RBF support. The default value for this option is
+currently `false`, so transactions will not opt into RBF by default. The new
+`bumpfee` RPC can be used to replace transactions that opt into RBF.
+
+Sensitive Data Is No Longer Stored In Debug Console History
+-----------------------------------------------------------
+
+The debug console maintains a history of previously entered commands that can be
+accessed by pressing the Up-arrow key so that users can easily reuse previously
+entered commands. Commands which have sensitive information such as passphrases and
+private keys will now have a `(...)` in place of the parameters when accessed through
+the history.
+
+Retaining the Mempool Across Restarts
+-------------------------------------
+
+The mempool will be saved to the data directory prior to shutdown
+to a `mempool.dat` file. This file preserves the mempool so that when the node
+restarts the mempool can be filled with transactions without waiting for new transactions
+to be created. This will also preserve any changes made to a transaction through
+commands such as `prioritisetransaction` so that those changes will not be lost.
+
+Final Alert
+-----------
+
+The Alert System was [disabled and deprecated](https://bitcoin.org/en/alert/2016-11-01-alert-retirement) in Bitcoin Core 0.12.1 and removed in 0.13.0.
+The Alert System was retired with a maximum sequence final alert which causes any nodes
+supporting the Alert System to display a static hard-coded "Alert Key Compromised" message which also
+prevents any other alerts from overriding it. This final alert is hard-coded into this release
+so that all old nodes receive the final alert.
+
+GUI Changes
+-----------
+
+ - After resetting the options by clicking the `Reset Options` button
+ in the options dialog or with the `-resetguioptions` startup option,
+ the user will be prompted to choose the data directory again. This
+ is to ensure that custom data directories will be kept after the
+ option reset which clears the custom data directory set via the choose
+ datadir dialog.
+
+ - Multiple peers can now be selected in the list of peers in the debug
+ window. This allows for users to ban or disconnect multiple peers
+ simultaneously instead of banning them one at a time.
+
+ - An indicator has been added to the bottom right hand corner of the main
+ window to indicate whether the wallet being used is a HD wallet. This
+ icon will be grayed out with an X on top of it if the wallet is not a
+ HD wallet.
+
+Low-level RPC changes
+----------------------
+
+ - `importprunedfunds` only accepts two required arguments. Some versions accept
+ an optional third arg, which was always ignored. Make sure to never pass more
+ than two arguments.
+
+ - The first boolean argument to `getaddednodeinfo` has been removed. This is
+ an incompatible change.
+
+ - RPC command `getmininginfo` loses the "testnet" field in favor of the more
+ generic "chain" (which has been present for years).
+
+ - A new RPC command `preciousblock` has been added which marks a block as
+ precious. A precious block will be treated as if it were received earlier
+ than a competing block.
+
+ - A new RPC command `importmulti` has been added which receives an array of
+ JSON objects representing the intention of importing a public key, a
+ private key, an address and script/p2sh
+
+ - Use of `getrawtransaction` for retrieving confirmed transactions with unspent
+ outputs has been deprecated. For now this will still work, but in the future
+ it may change to only be able to retrieve information about transactions in
+ the mempool or if `txindex` is enabled.
+
+ - A new RPC command `getmemoryinfo` has been added which will return information
+ about the memory usage of Bitcoin Core. This was added in conjunction with
+ optimizations to memory management. See [Pull #8753](https://github.com/bitcoin/bitcoin/pull/8753)
+ for more information.
+
+ - A new RPC command `bumpfee` has been added which allows replacing an
+ unconfirmed wallet transaction that signaled RBF (see the `-walletrbf`
+ startup option above) with a new transaction that pays a higher fee, and
+ should be more likely to get confirmed quickly.
+
+HTTP REST Changes
+-----------------
+
+ - UTXO set query (`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n>
+ /.../<txid>-<n>.<bin|hex|json>`) responses were changed to return status
+ code `HTTP_BAD_REQUEST` (400) instead of `HTTP_INTERNAL_SERVER_ERROR` (500)
+ when requests contain invalid parameters.
+
+Minimum Fee Rate Policies
+-------------------------
+
+Since the changes in 0.12 to automatically limit the size of the mempool and improve the performance of block creation in mining code it has not been important for relay nodes or miners to set `-minrelaytxfee`. With this release the following concepts that were tied to this option have been separated out:
+- incremental relay fee used for calculating BIP 125 replacement and mempool limiting. (1000 satoshis/kB)
+- calculation of threshold for a dust output. (effectively 3 * 1000 satoshis/kB)
+- minimum fee rate of a package of transactions to be included in a block created by the mining code. If miners wish to set this minimum they can use the new `-blockmintxfee` option. (defaults to 1000 satoshis/kB)
+
+The `-minrelaytxfee` option continues to exist but is recommended to be left unset.
+
+Fee Estimation Changes
+----------------------
+
+- Since 0.13.2 fee estimation for a confirmation target of 1 block has been
+ disabled. The fee slider will no longer be able to choose a target of 1 block.
+ This is only a minor behavior change as there was often insufficient
+ data for this target anyway. `estimatefee 1` will now always return -1 and
+ `estimatesmartfee 1` will start searching at a target of 2.
+
+- The default target for fee estimation is changed to 6 blocks in both the GUI
+ (previously 25) and for RPC calls (previously 2).
+
+Removal of Priority Estimation
+------------------------------
+
+- Estimation of "priority" needed for a transaction to be included within a target
+ number of blocks has been removed. The RPC calls are deprecated and will either
+ return -1 or 1e24 appropriately. The format for `fee_estimates.dat` has also
+ changed to no longer save these priority estimates. It will automatically be
+ converted to the new format which is not readable by prior versions of the
+ software.
+
+- Support for "priority" (coin age) transaction sorting for mining is
+ considered deprecated in Core and will be removed in the next major version.
+ This is not to be confused with the `prioritisetransaction` RPC which will remain
+ supported by Core for adding fee deltas to transactions.
+
+P2P connection management
+--------------------------
+
+- Peers manually added through the `-addnode` option or `addnode` RPC now have their own
+ limit of eight connections which does not compete with other inbound or outbound
+ connection usage and is not subject to the limitation imposed by the `-maxconnections`
+ option.
+
+- New connections to manually added peers are performed more quickly.
+
+Introduction of assumed-valid blocks
+-------------------------------------
+
+- A significant portion of the initial block download time is spent verifying
+ scripts/signatures. Although the verification must pass to ensure the security
+ of the system, no other result from this verification is needed: If the node
+ knew the history of a given block were valid it could skip checking scripts
+ for its ancestors.
+
+- A new configuration option 'assumevalid' is provided to express this knowledge
+ to the software. Unlike the 'checkpoints' in the past this setting does not
+ force the use of a particular chain: chains that are consistent with it are
+ processed quicker, but other chains are still accepted if they'd otherwise
+ be chosen as best. Also unlike 'checkpoints' the user can configure which
+ block history is assumed true, this means that even outdated software can
+ sync more quickly if the setting is updated by the user.
+
+- Because the validity of a chain history is a simple objective fact it is much
+ easier to review this setting. As a result the software ships with a default
+ value adjusted to match the current chain shortly before release. The use
+ of this default value can be disabled by setting -assumevalid=0
+
+Fundrawtransaction change address reuse
+----------------------------------------
+
+- Before 0.14, `fundrawtransaction` was by default wallet stateless. In
+ almost all cases `fundrawtransaction` does add a change-output to the
+ outputs of the funded transaction. Before 0.14, the used keypool key was
+ never marked as change-address key and directly returned to the keypool
+ (leading to address reuse). Before 0.14, calling `getnewaddress`
+ directly after `fundrawtransaction` did generate the same address as
+ the change-output address.
+
+- Since 0.14, fundrawtransaction does reserve the change-output-key from
+ the keypool by default (optional by setting `reserveChangeKey`, default =
+ `true`)
+
+- Users should also consider using `getrawchangeaddress()` in conjunction
+ with `fundrawtransaction`'s `changeAddress` option.
+
+Unused mempool memory used by coincache
+----------------------------------------
+
+- Before 0.14, memory reserved for mempool (using the `-maxmempool` option)
+ went unused during initial block download, or IBD. In 0.14, the UTXO DB cache
+ (controlled with the `-dbcache` option) borrows memory from the mempool
+ when there is extra memory available. This may result in an increase in
+ memory usage during IBD for those previously relying on only the `-dbcache`
+ option to limit memory during that time.
+
+0.14.0 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, minor refactors and string updates. For convenience
+in locating the code changes and accompanying discussion, both the pull request
+and git merge commit are mentioned.
+
+### RPC and other APIs
+- #8421 `b77bb95` httpserver: drop boost dependency (theuni)
+- #8638 `f061415` rest.cpp: change `HTTP_INTERNAL_SERVER_ERROR` to `HTTP_BAD_REQUEST` (djpnewton)
+- #8272 `91990ee` Make the dummy argument to getaddednodeinfo optional (sipa)
+- #8722 `bb843ad` bitcoin-cli: More detailed error reporting (laanwj)
+- #6996 `7f71a3c` Add preciousblock RPC (sipa)
+- #8788 `97c7f73` Give RPC commands more information about the RPC request (jonasschnelli)
+- #7948 `5d2c8e5` Augment getblockchaininfo bip9\_softforks data (mruddy)
+- #8980 `0e22855` importmulti: Avoid using boost::variant::operator!=, which is only in newer boost versions (luke-jr)
+- #9025 `4d8558a` Getrawtransaction should take a bool for verbose (jnewbery)
+- #8811 `5754e03` Add support for JSON-RPC named arguments (laanwj)
+- #9520 `2456a83` Deprecate non-txindex getrawtransaction and better warning (sipa)
+- #9518 `a65ced1` Return height of last block pruned by pruneblockchain RPC (ryanofsky)
+- #9222 `7cb024e` Add 'subtractFeeFromAmount' option to 'fundrawtransaction' (dooglus)
+- #8456 `2ef52d3` Simplified `bumpfee` command (mrbandrews)
+- #9516 `727a798` Bug-fix: listsinceblock: use fork point as reference for blocks in reorg'd chains (kallewoof)
+- #9640 `7bfb770` Bumpfee: bugfixes for error handling and feerate calculation (sdaftuar)
+- #9673 `8d6447e` Set correct metadata on bumpfee wallet transactions (ryanofsky)
+- #9650 `40f7e27` Better handle invalid parameters to signrawtransaction (TheBlueMatt)
+- #9682 `edc9e63` Require timestamps for importmulti keys (ryanofsky)
+- #9108 `d8e8b06` Use importmulti timestamp when importing watch only keys (on top of #9682) (ryanofsky)
+- #9756 `7a93af8` Return error when importmulti called with invalid address (ryanofsky)
+- #9778 `ad168ef` Add two hour buffer to manual pruning (morcos)
+- #9761 `9828f9a` Use 2 hour grace period for key timestamps in importmulti rescans (ryanofsky)
+- #9474 `48d7e0d` Mark the minconf parameter to move as ignored (sipa)
+- #9619 `861cb0c` Bugfix: RPC/Mining: GBT should return 1 MB sizelimit before segwit activates (luke-jr)
+- #9773 `9072395` Return errors from importmulti if complete rescans are not successful (ryanofsky)
+
+### Block and transaction handling
+- #8391 `37d83bb` Consensus: Remove ISM (NicolasDorier)
+- #8365 `618c9dd` Treat high-sigop transactions as larger rather than rejecting them (sipa)
+- #8814 `14b7b3f` wallet, policy: ParameterInteraction: Don't allow 0 fee (MarcoFalke)
+- #8515 `9bdf526` A few mempool removal optimizations (sipa)
+- #8448 `101c642` Store mempool and prioritization data to disk (sipa)
+- #7730 `3c03dc2` Remove priority estimation (morcos)
+- #9111 `fb15610` Remove unused variable `UNLIKELY_PCT` from fees.h (fanquake)
+- #9133 `434e683` Unset fImporting for loading mempool (morcos)
+- #9179 `b9a87b4` Set `DEFAULT_LIMITFREERELAY` = 0 kB/minute (MarcoFalke)
+- #9239 `3fbf079` Disable fee estimates for 1-block target (morcos)
+- #7562 `1eef038` Bump transaction version default to 2 (btcdrak)
+- #9313,#9367 If we don't allow free txs, always send a fee filter (morcos)
+- #9346 `b99a093` Batch construct batches (sipa)
+- #9262 `5a70572` Prefer coins that have fewer ancestors, sanity check txn before ATMP (instagibbs)
+- #9288 `1ce7ede` Fix a bug if the min fee is 0 for FeeFilterRounder (morcos)
+- #9395 `0fc1c31` Add test for `-walletrejectlongchains` (morcos)
+- #9107 `7dac1e5` Safer modify new coins (morcos)
+- #9312 `a72f76c` Increase mempool expiry time to 2 weeks (morcos)
+- #8610 `c252685` Share unused mempool memory with coincache (sipa)
+- #9138 `f646275` Improve fee estimation (morcos)
+- #9408 `46b249e` Allow shutdown during LoadMempool, dump only when necessary (jonasschnelli)
+- #9310 `8c87f17` Assert FRESH validity in CCoinsViewCache::BatchWrite (ryanofsky)
+- #7871 `e2e624d` Manual block file pruning (mrbandrews)
+- #9507 `0595042` Fix use-after-free in CTxMemPool::removeConflicts() (sdaftuar)
+- #9380 `dd98f04` Separate different uses of minimum fees (morcos)
+- #9596 `71148b8` bugfix save feeDelta instead of priorityDelta in DumpMempool (morcos)
+- #9371 `4a1dc35` Notify on removal (morcos)
+- #9519 `9b4d267` Exclude RBF replacement txs from fee estimation (morcos)
+- #8606 `e2a1a1e` Fix some locks (sipa)
+- #8681 `6898213` Performance Regression Fix: Pre-Allocate txChanged vector (JeremyRubin)
+- #8223 `744d265` c++11: Use std::unique\_ptr for block creation (domob1812)
+- #9125 `7490ae8` Make CBlock a vector of shared\_ptr of CTransactions (sipa)
+- #8930 `93566e0` Move orphan processing to ActivateBestChain (TheBlueMatt)
+- #8580 `46904ee` Make CTransaction actually immutable (sipa)
+- #9240 `a1dcf2e` Remove txConflicted (morcos)
+- #8589 `e8cfe1e` Inline CTxInWitness inside CTxIn (sipa)
+- #9349 `2db4cbc` Make CScript (and prevector) c++11 movable (sipa)
+- #9252 `ce5c1f4` Release cs\_main before calling ProcessNewBlock, or processing headers (cmpctblock handling) (sdaftuar)
+- #9283 `869781c` A few more CTransactionRef optimizations (sipa)
+- #9499 `9c9af5a` Use recent-rejects, orphans, and recently-replaced txn for compact-block-reconstruction (TheBlueMatt)
+- #9813 `3972a8e` Read/write mempool.dat as a binary (paveljanik)
+
+### P2P protocol and network code
+- #8128 `1030fa7` Turn net structures into dumb storage classes (theuni)
+- #8282 `026c6ed` Feeler connections to increase online addrs in the tried table (EthanHeilman)
+- #8462 `53f8f22` Move AdvertiseLocal debug output to net category (Mirobit)
+- #8612 `84decb5` Check for compatibility with download in FindNextBlocksToDownload (sipa)
+- #8594 `5b2ea29` Do not add random inbound peers to addrman (gmaxwell)
+- #8085 `6423116` Begin encapsulation (theuni)
+- #8715 `881d7ea` only delete CConnman if it's been created (theuni)
+- #8707 `f07424a` Fix maxuploadtarget setting (theuni)
+- #8661 `d2e4655` Do not set an addr time penalty when a peer advertises itself (gmaxwell)
+- #8822 `9bc6a6b` Consistent checksum handling (laanwj)
+- #8936 `1230890` Report NodeId in misbehaving debug (rebroad)
+- #8968 `3cf496d` Don't hold cs\_main when calling ProcessNewBlock from a cmpctblock (TheBlueMatt)
+- #9002 `e1d1f57` Make connect=0 disable automatic outbound connections (gmaxwell)
+- #9050 `fcf61b8` Make a few values immutable, and use deterministic randomness for the localnonce (theuni)
+- #8969 `3665483` Decouple peer-processing-logic from block-connection-logic (#2) (TheBlueMatt)
+- #8708 `c8c572f` have CConnman handle message sending (theuni)
+- #8709 `1e50d22` Allow filterclear messages for enabling TX relay only (rebroad)
+- #9045 `9f554e0` Hash P2P messages as they are received instead of at process-time (TheBlueMatt)
+- #9026 `dc6b940` Fix handling of invalid compact blocks (sdaftuar)
+- #8996 `ab914a6` Network activity toggle (luke-jr)
+- #9131 `62af164` fNetworkActive is not protected by a lock, use an atomic (jonasschnelli)
+- #8872 `0c577f2` Remove block-request logic from INV message processing (TheBlueMatt)
+- #8690 `791b58d` Do not fully sort all nodes for addr relay (sipa)
+- #9128 `76fec09` Decouple CConnman and message serialization (theuni)
+- #9226 `3bf06e9` Remove fNetworkNode and pnodeLocalHost (gmaxwell)
+- #9352 `a7f7651` Attempt reconstruction from all compact block announcements (sdaftuar)
+- #9319 `a55716a` Break addnode out from the outbound connection limits (gmaxwell)
+- #9261 `2742568` Add unstored orphans with rejected parents to recentRejects (morcos)
+- #9441 `8b66bf7` Massive speedup. Net locks overhaul (theuni)
+- #9375 `3908fc4` Relay compact block messages prior to full block connection (TheBlueMatt)
+- #9400 `8a445c5` Set peers as HB peers upon full block validation (instagibbs)
+- #9561 `6696b46` Wake message handling thread when we receive a new block (TheBlueMatt)
+- #9535 `82274c0` Split CNode::cs\_vSend: message processing and message sending (TheBlueMatt)
+- #9606 `3f9f962` Consistently use GetTimeMicros() for inactivity checks (sdaftuar)
+- #9594 `fd70211` Send final alert message to older peers after connecting (gmaxwell)
+- #9626 `36966a1` Clean up a few CConnman cs\_vNodes/CNode things (TheBlueMatt)
+- #9609 `4966917` Fix remaining net assertions (theuni)
+- #9671 `7821db3` Fix super-unlikely race introduced in 236618061a445d2cb11e72 (TheBlueMatt)
+- #9730 `33f3b21` Remove bitseed.xf2.org form the dns seed list (jonasschnelli)
+- #9698 `2447c10` Fix socket close race (theuni)
+- #9708 `a06ede9` Clean up all known races/platform-specific UB at the time PR was opened (TheBlueMatt)
+- #9715 `b08656e` Disconnect peers which we do not receive VERACKs from within 60 sec (TheBlueMatt)
+- #9720 `e87ce95` Fix banning and disallow sending messages before receiving verack (theuni)
+- #9268 `09c4fd1` Fix rounding privacy leak introduced in #9260 (TheBlueMatt)
+- #9075 `9346f84` Decouple peer-processing-logic from block-connection-logic (#3) (TheBlueMatt)
+- #8688 `047ded0` Move static global randomizer seeds into CConnman (sipa)
+- #9289 `d9ae1ce` net: drop boost::thread\_group (theuni)
+
+### Validation
+- #9014 `d04aeba` Fix block-connection performance regression (TheBlueMatt)
+- #9299 `d52ce89` Remove no longer needed check for premature v2 txs (morcos)
+- #9273 `b68685a` Remove unused `CDiskBlockPos*` argument from ProcessNewBlock (TheBlueMatt)
+- #8895 `b83264d` Better SigCache Implementation (JeremyRubin)
+- #9490 `e126d0c` Replace FindLatestBefore used by importmulti with FindEarliestAtLeast (gmaxwell)
+- #9484 `812714f` Introduce assumevalid setting to skip validation presumed valid scripts (gmaxwell)
+- #9511 `7884956` Don't overwrite validation state with corruption check (morcos)
+- #9765 `1e92e04` Harden against mistakes handling invalid blocks (sdaftuar)
+- #9779 `3c02b95` Update nMinimumChainWork and defaultAssumeValid (gmaxwell)
+- #8524 `19b0f33` Precompute sighashes (sipa)
+- #9791 `1825a03` Avoid VLA in hash.h (sipa)
+
+### Build system
+- #8238 `6caf3ee` ZeroMQ 4.1.5 && ZMQ on Windows (fanquake)
+- #8520 `b40e19c` Remove check for `openssl/ec.h` (laanwj)
+- #8617 `de07fdc` Include instructions to extract Mac OS X SDK on Linux using 7zip and SleuthKit (luke-jr)
+- #8566 `7b98895` Easy to use gitian building script (achow101)
+- #8604 `f256843` build,doc: Update for 0.13.0+ and OpenBSD 5.9 (laanwj)
+- #8640 `2663e51` depends: Remove Qt46 package (fanquake)
+- #8645 `8ea4440` Remove unused Qt 4.6 patch (droark)
+- #8608 `7e9ab95` Install manpages via make install, also add some autogenerated manpages (nomnombtc)
+- #8781 `ca69ef4` contrib: delete `qt_translations.py` (MarcoFalke)
+- #8783 `64dc645` share: remove qt/protobuf.pri (MarcoFalke)
+- #8423 `3166dff` depends: expat 2.2.0, ccache 3.3.1, fontconfig 2.12.1 (fanquake)
+- #8791 `b694b0d` travis: cross-mac: explicitly enable gui (MarcoFalke)
+- #8820 `dc64141` depends: Fix Qt compilation with Xcode 8 (fanquake)
+- #8730 `489a6ab` depends: Add libevent compatibility patch for windows (laanwj)
+- #8819 `c841816` depends: Boost 1.61.0 (fanquake)
+- #8826 `f560d95` Do not include `env_win.cc` on non-Windows systems (paveljanik)
+- #8948 `e077e00` Reorder Windows gitian build order to match Linux (Michagogo)
+- #8568 `078900d` new var `DIST_CONTRIB` adds useful things for packagers from contrib (nomnombtc)
+- #9114 `21e6c6b` depends: Set `OSX_MIN_VERSION` to 10.8 (fanquake)
+- #9140 `018a4eb` Bugfix: Correctly replace generated headers and fail cleanly (luke-jr)
+- #9156 `a8b2a82` Add compile and link options echo to configure (jonasschnelli)
+- #9393 `03d85f6` Include cuckoocache header in Makefile (MarcoFalke)
+- #9420 `bebe369` Fix linker error when configured with --enable-lcov (droark)
+- #9412 `53442af` Fix 'make deploy' for OSX (jonasschnelli)
+- #9475 `7014506` Let autoconf detect presence of `EVP_MD_CTX_new` (luke-jr)
+- #9513 `bbf193f` Fix qt distdir builds (theuni)
+- #9471 `ca615e6` depends: libevent 2.1.7rc (fanquake)
+- #9468 `f9117f2` depends: Dependency updates for 0.14.0 (fanquake)
+- #9469 `01c4576` depends: Qt 5.7.1 (fanquake)
+- #9574 `5ac6687` depends: Fix QT build on OSX (fanquake)
+- #9646 `720b579` depends: Fix cross build for qt5.7 (theuni)
+- #9705 `6a55515` Add options to override BDB cflags/libs (laanwj)
+- #8249 `4e1567a` Enable (and check for) 64-bit ASLR on Windows (laanwj)
+- #9758 `476cc47` Selectively suppress deprecation warnings (jonasschnelli)
+- #9783 `6d61a2b` release: bump gitian descriptors for a new 0.14 package cache (theuni)
+- #9789 `749fe95` build: add --enable-werror and warn on vla's (theuni)
+- #9831 `99fd85c` build: force a c++ standard to be specified (theuni)
+
+### GUI
+- #8192 `c503863` Remove URLs from About dialog translations (fanquake)
+- #8540 `36404ae` Fix random segfault when closing "Choose data directory" dialog (laanwj)
+- #8517 `2468292` Show wallet HD state in statusbar (jonasschnelli)
+- #8463 `62a5a8a` Remove Priority from coincontrol dialog (MarcoFalke)
+- #7579 `0606f95` Show network/chain errors in the GUI (jonasschnelli)
+- #8583 `c19f8a4` Show XTHIN in GUI (rebroad)
+- #7783 `4335d5a` RPC-Console: support nested commands and simple value queries (jonasschnelli)
+- #8672 `6052d50` Show transaction size in transaction details window (Cocosoft)
+- #8777 `fec6af7` WalletModel: Expose disablewallet (MarcoFalke)
+- #8371 `24f72e9` Add out-of-sync modal info layer (jonasschnelli)
+- #8885 `b2fec4e` Fix ban from qt console (theuni)
+- #8821 `bf8e68a` sync-overlay: Don't block during reindex (MarcoFalke)
+- #8906 `088d1f4` sync-overlay: Don't show progress twice (MarcoFalke)
+- #8918 `47ace42` Add "Copy URI" to payment request context menu (luke-jr)
+- #8925 `f628d9a` Display minimum ping in debug window (rebroad)
+- #8774 `3e942a7` Qt refactors to better abstract wallet access (luke-jr)
+- #8985 `7b1bfa3` Use pindexBestHeader instead of setBlockIndexCandidates for NotifyHeaderTip() (jonasschnelli)
+- #8989 `d2143dc` Overhaul smart-fee slider, adjust default confirmation target (jonasschnelli)
+- #9043 `273bde3` Return useful error message on ATMP failure (MarcoFalke)
+- #9088 `4e57824` Reduce ambiguity of warning message (rebroad)
+- #8874 `e984730` Multiple Selection for peer and ban tables (achow101)
+- #9145 `924745d` Make network disabled icon 50% opaque (MarcoFalke)
+- #9130 `ac489b2` Mention the new network toggle functionality in the tooltip (paveljanik)
+- #9218 `4d955fc` Show progress overlay when clicking spinner icon (laanwj)
+- #9280 `e15660c` Show ModalOverlay by pressing the progress bar, allow hiding (jonasschnelli)
+- #9296 `fde7d99` Fix missed change to WalletTx structure (morcos)
+- #9266 `2044e37` Bugfix: Qt/RPCConsole: Put column enum in the right places (luke-jr)
+- #9255 `9851a84` layoutAboutToChange signal is called layoutAboutToBeChanged (laanwj)
+- #9330 `47e6a19` Console: add security warning (jonasschnelli)
+- #9329 `db45ad8` Console: allow empty arguments (jonasschnelli)
+- #8877 `6dc4c43` Qt RPC console: history sensitive-data filter, and saving input line when browsing history (luke-jr)
+- #9462 `649cf5f` Do not translate tilde character (MarcoFalke)
+- #9457 `123ea73` Select more files for translation (MarcoFalke)
+- #9413 `fd7d8c7` CoinControl: Allow non-wallet owned change addresses (jonasschnelli)
+- #9461 `b250686` Improve progress display during headers-sync and peer-finding (jonasschnelli)
+- #9588 `5086452` Use nPowTargetSpacing constant (MarcoFalke)
+- #9637 `d9e4d1d` Fix transaction details output-index to reflect vout index (jonasschnelli)
+- #9718 `36f9d3a` Qt/Intro: Various fixes (luke-jr)
+- #9735 `ec66d06` devtools: Handle Qt formatting characters edge-case in update-translations.py (laanwj)
+- #9755 `a441db0` Bugfix: Qt/Options: Restore persistent "restart required" notice (luke-jr)
+- #9817 `7d75a5a` Fix segfault crash when shutdown the GUI in disablewallet mode (jonasschnelli)
+
+### Wallet
+- #8152 `b9c1cd8` Remove `CWalletDB*` parameter from CWallet::AddToWallet (pstratem)
+- #8432 `c7e05b3` Make CWallet::fFileBacked private (pstratem)
+- #8445 `f916700` Move CWallet::setKeyPool to private section of CWallet (pstratem)
+- #8564 `0168019` Remove unused code/conditions in ReadAtCursor (jonasschnelli)
+- #8601 `37ac678` Add option to opt into full-RBF when sending funds (rebase, original by petertodd) (laanwj)
+- #8494 `a5b20ed` init, wallet: ParameterInteraction() iff wallet enabled (MarcoFalke)
+- #8760 `02ac669` init: Get rid of some `ENABLE_WALLET` (MarcoFalke)
+- #8696 `a1f8d3e` Wallet: Remove last external reference to CWalletDB (pstratem)
+- #8768 `886e8c9` init: Get rid of fDisableWallet (MarcoFalke)
+- #8486 `ab0b411` Add high transaction fee warnings (MarcoFalke)
+- #8851 `940748b` Move key derivation logic from GenerateNewKey to DeriveNewChildKey (pstratem)
+- #8287 `e10af96` Set fLimitFree = true (MarcoFalke)
+- #8928 `c587577` Fix init segfault where InitLoadWallet() calls ATMP before genesis (TheBlueMatt)
+- #7551 `f2d7056` Add importmulti RPC call (pedrobranco)
+- #9016 `0dcb888` Return useful error message on ATMP failure (instagibbs)
+- #8753 `f8723d2` Locked memory manager (laanwj)
+- #8828 `a4fd8df` Move CWalletDB::ReorderTransactions to CWallet (pstratem)
+- #8977 `6a1343f` Refactor wallet/init interaction (Reaccept wtx, flush thread) (jonasschnelli)
+- #9036 `ed0cc50` Change default confirm target from 2 to 6 (laanwj)
+- #9071 `d1871da` Declare wallet.h functions inline (sipa)
+- #9132 `f54e460` Make strWalletFile const (jonasschnelli)
+- #9141 `5ea5e04` Remove unnecessary calls to CheckFinalTx (jonasschnelli)
+- #9165 `c01f16a` SendMoney: use already-calculated balance (instagibbs)
+- #9311 `a336d13` Flush wallet after abandontransaction (morcos)
+- #8717 `38e4887` Addition of ImmatureCreditCached to MarkDirty() (spencerlievens)
+- #9446 `510c0d9` SetMerkleBranch: remove unused code, remove cs\_main lock requirement (jonasschnelli)
+- #8776 `2a524b8` Wallet refactoring leading up to multiwallet (luke-jr)
+- #9465 `a7d55c9` Do not perform ECDSA signing in the fee calculation inner loop (gmaxwell)
+- #9404 `12e3112` Smarter coordination of change and fee in CreateTransaction (morcos)
+- #9377 `fb75cd0` fundrawtransaction: Keep change-output keys by default, make it optional (jonasschnelli)
+- #9578 `923dc44` Add missing mempool lock for CalculateMemPoolAncestors (TheBlueMatt)
+- #9227 `02464da` Make nWalletDBUpdated atomic to avoid a potential race (pstratem)
+- #9764 `f8af89a` Prevent "overrides a member function but is not marked 'override'" warnings (laanwj)
+- #9771 `e43a585` Add missing cs\_wallet lock that triggers new lock held assertion (ryanofsky)
+- #9316 `3097ea4` Disable free transactions when relay is disabled (MarcoFalke)
+- #9615 `d2c9e4d` Wallet incremental fee (morcos)
+- #9760 `40c754c` Remove importmulti always-true check (ryanofsky)
+
+### Tests and QA
+- #8270 `6e5e5ab` Tests: Use portable #! in python scripts (/usr/bin/env) (ChoHag)
+- #8534,#8504 Remove java comparison tool (laanwj,MarcoFalke)
+- #8482 `740cff5` Use single cache dir for chains (MarcoFalke)
+- #8450 `21857d2` Replace `rpc_wallet_tests.cpp` with python RPC unit tests (pstratem)
+- #8671 `ddc3080` Minimal fix to slow prevector tests as stopgap measure (JeremyRubin)
+- #8680 `666eaf0` Address Travis spurious failures (theuni)
+- #8789 `e31a43c` pull-tester: Only print output when failed (MarcoFalke)
+- #8810 `14e8f99` tests: Add exception error message for JSONRPCException (laanwj)
+- #8830 `ef0801b` test: Add option to run bitcoin-util-test.py manually (jnewbery)
+- #8881 `e66cc1d` Add some verbose logging to bitcoin-util-test.py (jnewbery)
+- #8922 `0329511` Send segwit-encoded blocktxn messages in p2p-compactblocks (TheBlueMatt)
+- #8873 `74dc388` Add microbenchmarks to profile more code paths (ryanofsky)
+- #9032 `6a8be7b` test: Add format-dependent comparison to bctest (laanwj)
+- #9023 `774db92` Add logging to bitcoin-util-test.py (jnewbery)
+- #9065 `c9bdf9a` Merge `doc/unit-tests.md` into `src/test/README.md` (laanwj)
+- #9069 `ed64bce` Clean up bctest.py and bitcoin-util-test.py (jnewbery)
+- #9095 `b8f43e3` test: Fix test\_random includes (MarcoFalke)
+- #8894 `faec09b` Testing: Include fRelay in mininode version messages (jnewbery)
+- #9097 `e536499` Rework `sync_*` and preciousblock.py (MarcoFalke)
+- #9049 `71bc39e` Remove duplicatable duplicate-input check from CheckTransaction (TheBlueMatt)
+- #9136 `b422913` sync\_blocks cleanup (ryanofsky)
+- #9151 `4333b1c` proxy\_test: Calculate hardcoded port numbers (MarcoFalke)
+- #9206 `e662d28` Make test constant consistent with consensus.h (btcdrak)
+- #9139 `0de7fd3` Change sync\_blocks to pick smarter maxheight (on top of #9196) (ryanofsky)
+- #9100 `97ec6e5` tx\_valid: re-order inputs to how they are encoded (dcousens)
+- #9202 `e56cf67` bench: Add support for measuring CPU cycles (laanwj)
+- #9223 `5412c08` unification of Bloom filter representation (s-matthew-english)
+- #9257 `d7ba4a2` Dump debug logs on travis failures (sdaftuar)
+- #9221 `9e4bb31` Get rid of duplicate code (MarcoFalke)
+- #9274 `919db03` Use cached utxo set to fix performance regression (MarcoFalke)
+- #9276 `ea33f19` Some minor testing cleanups (morcos)
+- #9291 `8601784` Remove mapOrphanTransactionsByPrev from DoS\_tests (sipa)
+- #9309 `76fcd9d` Wallet needs to stay unlocked for whole test (morcos)
+- #9172 `5bc209c` Resurrect pstratem's "Simple fuzzing framework" (laanwj)
+- #9331 `c6fd923` Add test for rescan feature of wallet key import RPCs (ryanofsky)
+- #9354 `b416095` Make fuzzer actually test CTxOutCompressor (sipa)
+- #9390,#9416 travis: make distdir (MarcoFalke)
+- #9308 `0698639` test: Add CCoinsViewCache Access/Modify/Write tests (ryanofsky)
+- #9406 `0f921e6` Re-enable a blank v1 Tx JSON test (droark)
+- #9435 `dbc8a8c` Removed unused variable in test, fixing warning (ryanofsky)
+- #9436 `dce853e` test: Include tx data in `EXTRA_DIST` (MarcoFalke)
+- #9525 `02e5308` test: Include tx data in `EXTRA_DIST` (MarcoFalke)
+- #9498 `054d664` Basic CCheckQueue Benchmarks (JeremyRubin)
+- #9554 `0b96abc` test: Avoid potential NULL pointer dereference in `addrman_tests.cpp` (practicalswift)
+- #9628 `f895023` Increase a sync\_blocks timeout in pruning.py (sdaftuar)
+- #9638 `a7ea2f8` Actually test assertions in pruning.py (MarcoFalke)
+- #9647 `e99f0d7` Skip RAII event tests if libevent is built without `event_set_mem_functions` (luke-jr)
+- #9691 `fc67cd2` Init ECC context for `test_bitcoin_fuzzy` (gmaxwell)
+- #9712 `d304fef` bench: Fix initialization order in registration (laanwj)
+- #9707 `b860915` Fix RPC failure testing (jnewbery)
+- #9269 `43e8150` Align struct COrphan definition (sipa)
+- #9820 `599c69a` Fix pruning test broken by 2 hour manual prune window (ryanofsky)
+- #9824 `260c71c` qa: Check return code when stopping nodes (MarcoFalke)
+- #9875 `50953c2` tests: Fix dangling pwalletMain pointer in wallet tests (laanwj)
+- #9839 `eddaa6b` [qa] Make import-rescan.py watchonly check reliable (ryanofsky)
+
+### Documentation
+- #8332 `806b9e7` Clarify witness branches in transaction.h serialization (dcousens)
+- #8935 `0306978` Documentation: Building on Windows with WSL (pooleja)
+- #9144 `c98f6b3` Correct waitforblockheight example help text (fanquake)
+- #9407 `041331e` Added missing colons in when running help command (anditto)
+- #9378 `870cd2b` Add documentation for CWalletTx::fFromMe member (ryanofsky)
+- #9297 `0b73807` Various RPC help outputs updated (Mirobit)
+- #9613 `07421cf` Clarify getbalance help string to explain interaction with bumpfee (ryanofsky)
+- #9663 `e30d928` Clarify listunspent amount description (instagibbs)
+- #9396 `d65a13b` Updated listsinceblock rpc documentation (accraze)
+- #8747 `ce43630` rpc: Fix transaction size comments and RPC help text (jnewbery)
+- #8058 `bbd9740` Doc: Add issue template (AmirAbrams)
+- #8567 `85d4e21` Add default port numbers to REST doc (djpnewton)
+- #8624 `89de153` build: Mention curl (MarcoFalke)
+- #8786 `9da7366` Mandatory copyright agreement (achow101)
+- #8823 `7b05af6` Add privacy recommendation when running hidden service (laanwj)
+- #9433 `caa2f10` Update the Windows build notes (droark)
+- #8879 `f928050` Rework docs (MarcoFalke)
+- #8887 `61d191f` Improve GitHub issue template (fanquake)
+- #8787 `279bbad` Add missing autogen to example builds (AmirAbrams)
+- #8892 `d270c30` Add build instructions for FreeBSD (laanwj)
+- #8890 `c71a654` Update Doxygen configuration file (fanquake)
+- #9207 `fa1f944` Move comments above bash command in build-unix (AmirAbrams)
+- #9219 `c4522e7` Improve windows build instructions using Linux subsystem (laanwj)
+- #8954 `932d02a` contrib: Add README for pgp keys (MarcoFalke)
+- #9093 `2fae5b9` release-process: Mention GitHub release and archived release notes (MarcoFalke)
+- #8743 `bae178f` Remove old manpages from contrib/debian in favour of doc/man (fanquake)
+- #9550 `4105cb6` Trim down the XP notice and say more about what we support (gmaxwell)
+- #9246 `9851498` Developer docs about existing subtrees (gmaxwell)
+- #9401 `c2ea1e6` Make rpcauth help message clearer, add example in example .conf (instagibbs)
+- #9022,#9033 Document dropping OS X 10.7 support (fanquake, MarcoFalke)
+- #8771 `bc9e3ab` contributing: Mention not to open several pulls (luke-jr)
+- #8852 `7b784cc` Mention Gitian building script in doc (Laudaa) (laanwj)
+- #8915 `03dd707` Add copyright/patent issues to possible NACK reasons (petertodd)
+- #8965 `23e03f8` Mention that PPA doesn't support Debian (anduck)
+- #9115 `bfc7aad` Mention reporting security issues responsibly (paveljanik)
+- #9840 `08e0690` Update sendfrom RPC help to correct coin selection misconception (ryanofsky)
+- #9865 `289204f` Change bitcoin address in RPC help message (marijnfs)
+
+### Miscellaneous
+- #8274 `7a2d402` util: Update tinyformat (laanwj)
+- #8291 `5cac8b1` util: CopyrightHolders: Check for untranslated substitution (MarcoFalke)
+- #8557 `44691f3` contrib: Rework verifybinaries (MarcoFalke)
+- #8621 `e8ed6eb` contrib: python: Don't use shell=True (MarcoFalke)
+- #8813 `fb24d7e` bitcoind: Daemonize using daemon(3) (laanwj)
+- #9004 `67728a3` Clarify `listenonion` (unsystemizer)
+- #8674 `bae81b8` tools for analyzing, updating and adding copyright headers in source files (isle2983)
+- #8976 `8c6218a` libconsensus: Add input validation of flags (laanwj)
+- #9112 `46027e8` Avoid ugly exception in log on unknown inv type (laanwj)
+- #8837 `2108911` Allow bitcoin-tx to parse partial transactions (jnewbery)
+- #9204 `74ced54` Clarify CreateTransaction error messages (instagibbs)
+- #9265 `31bcc66` bitcoin-cli: Make error message less confusing (laanwj)
+- #9303 `72bf1b3` Update comments in ctaes (sipa)
+- #9417 `c4b7d4f` Do not evaluate hidden LogPrint arguments (sipa)
+- #9506 `593a00c` RFC: Improve style for if indentation (sipa)
+- #8883 `d5d4ad8` Add all standard TXO types to bitcoin-tx (jnewbery)
+- #9531 `23281a4` Release notes for estimation changes (morcos)
+- #9486 `f62bc10` Make peer=%d log prints consistent (TheBlueMatt)
+- #9552 `41cb05c` Add IPv6 support to qos.sh (jamesmacwhite)
+- #9542 `e9e7993` Docs: Update CONTRIBUTING.md (jnewbery)
+- #9649 `53ab12d` Remove unused clang format dev script (MarcoFalke)
+- #9625 `77bd8c4` Increase minimum debug.log size to 10MB after shrink (morcos)
+- #9070 `7b22e50` Lockedpool fixes (kazcw)
+- #8779 `7008e28` contrib: Delete spendfrom (MarcoFalke)
+- #9587,#8793,#9496,#8191,#8109,#8655,#8472,#8677,#8981,#9124 Avoid shadowing of variables (paveljanik)
+- #9063 `f2a6e82` Use deprecated `MAP_ANON` if `MAP_ANONYMOUS` is not defined (paveljanik)
+- #9060 `1107653` Fix bloom filter init to isEmpty = true (robmcl4)
+- #8613 `613bda4` LevelDB 1.19 (sipa)
+- #9225 `5488514` Fix some benign races (TheBlueMatt)
+- #8736 `5fa7b07` base58: Improve DecodeBase58 performance (wjx)
+- #9039 `e81df49` Various serialization simplifcations and optimizations (sipa)
+- #9010 `a143b88` Split up AppInit2 into multiple phases, daemonize after datadir lock errors (laanwj)
+- #9230 `c79e52a` Fix some benign races in timestamp logging (TheBlueMatt)
+- #9183,#9260 Mrs Peacock in The Library with The Candlestick (killed main.{h,cpp}) (TheBlueMatt)
+- #9236 `7f72568` Fix races for strMiscWarning and `fLargeWork*Found`, make QT runawayException use GetWarnings (gmaxwell)
+- #9243 `7aa7004` Clean up mapArgs and mapMultiArgs Usage (TheBlueMatt)
+- #9387 `cfe41d7` RAII of libevent stuff using unique ptrs with deleters (kallewoof)
+- #9472 `fac0f30` Disentangle progress estimation from checkpoints and update it (sipa)
+- #9512 `6012967` Fix various things -fsanitize complains about (sipa)
+- #9373,#9580 Various linearization script issues (droark)
+- #9674 `dd163f5` Lock debugging: Always enforce strict lock ordering (try or not) (TheBlueMatt)
+- #8453,#9334 Update to latest libsecp256k1 (laanwj,sipa)
+- #9656 `7c93952` Check verify-commits on pushes to master (TheBlueMatt)
+- #9679 `a351162` Access WorkQueue::running only within the cs lock (TheBlueMatt)
+- #9777 `8dee822` Handle unusual maxsigcachesize gracefully (jnewbery)
+- #8863,#8807 univalue: Pull subtree (MarcoFalke)
+- #9798 `e22c067` Fix Issue #9775 (Check returned value of fopen) (kirit93)
+- #9856 `69832aa` Terminate immediately when allocation fails (theuni)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- accraze
+- adlawren
+- Alex Morcos
+- Alexey Vesnin
+- Amir Abrams
+- Anders Øyvind Urke-Sætre
+- Anditto Heristyo
+- Andrew Chow
+- anduck
+- Anthony Towns
+- Brian Deery
+- BtcDrak
+- Chris Moore
+- Chris Stewart
+- Christian Barcenas
+- Christian Decker
+- Cory Fields
+- crowning-
+- CryptAxe
+- CryptoVote
+- Dagur Valberg Johannsson
+- Daniel Cousens
+- Daniel Kraft
+- Derek Miller
+- djpnewton
+- Don Patterson
+- Doug
+- Douglas Roark
+- Ethan Heilman
+- fsb4000
+- Gaurav Rana
+- Geoffrey Tsui
+- Greg Walker
+- Gregory Maxwell
+- Gregory Sanders
+- Hampus Sjöberg
+- isle2983
+- Ivo van der Sangen
+- James White
+- Jameson Lopp
+- Jeremy Rubin
+- Jiaxing Wang
+- jnewbery
+- John Newbery
+- Johnson Lau
+- Jon Lund Steffensen
+- Jonas Schnelli
+- jonnynewbs
+- Jorge Timón
+- Justin Camarena
+- Karl-Johan Alm
+- Kaz Wesley
+- kirit93
+- Koki Takahashi
+- Lauda
+- leijurv
+- lizhi
+- Luke Dashjr
+- maiiz
+- MarcoFalke
+- Marijn Stollenga
+- Marty Jones
+- Masahiko Hyuga
+- Matt Corallo
+- Matthew King
+- matthias
+- Micha
+- Michael Ford
+- Michael Rotarius
+- Mitchell Cash
+- mrbandrews
+- mruddy
+- Nicolas DORIER
+- nomnombtc
+- Patrick Strateman
+- Pavel Janík
+- Pedro Branco
+- Peter Todd
+- Pieter Wuille
+- poole\_party
+- practicalswift
+- R E Broadley
+- randy-waterhouse
+- Richard Kiss
+- Robert McLaughlin
+- rodasmith
+- Russell Yanofsky
+- S. Matthew English
+- Sev
+- Spencer Lievens
+- Stanislas Marion
+- Steven
+- Suhas Daftuar
+- Thomas Snider
+- UdjinM6
+- unsystemizer
+- whythat
+- Will Binns
+- Wladimir J. van der Laan
+- wodry
+- Zak Wilcox
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
diff --git a/doc/release-notes/release-notes-0.14.1.md b/doc/release-notes/release-notes-0.14.1.md
new file mode 100644
index 0000000000..ef072afd4d
--- /dev/null
+++ b/doc/release-notes/release-notes-0.14.1.md
@@ -0,0 +1,143 @@
+Bitcoin Core version 0.14.1 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.14.1/>
+
+This is a new minor version release, including various bugfixes and
+performance improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+Compatibility
+==============
+
+Bitcoin Core is extensively tested on multiple operating systems using
+the Linux kernel, macOS 10.8+, and Windows Vista and later.
+
+Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support),
+No attempt is made to prevent installing or running the software on Windows XP, you
+can still do so at your own risk but be aware that there are known instabilities and issues.
+Please do not report issues about Windows XP to the issue tracker.
+
+Bitcoin Core should also work on most other Unix-like systems but is not
+frequently tested on them.
+
+Notable changes
+===============
+
+RPC changes
+-----------
+
+- The first positional argument of `createrawtransaction` was renamed from
+ `transactions` to `inputs`.
+
+- The argument of `disconnectnode` was renamed from `node` to `address`.
+
+These interface changes break compatibility with 0.14.0, when the named
+arguments functionality, introduced in 0.14.0, is used. Client software
+using these calls with named arguments needs to be updated.
+
+Mining
+------
+
+In previous versions, getblocktemplate required segwit support from downstream
+clients/miners once the feature activated on the network. In this version, it
+now supports non-segwit clients even after activation, by removing all segwit
+transactions from the returned block template. This allows non-segwit miners to
+continue functioning correctly even after segwit has activated.
+
+Due to the limitations in previous versions, getblocktemplate also recommended
+non-segwit clients to not signal for the segwit version-bit. Since this is no
+longer an issue, getblocktemplate now always recommends signalling segwit for
+all miners. This is safe because ability to enforce the rule is the only
+required criteria for safe activation, not actually producing segwit-enabled
+blocks.
+
+UTXO memory accounting
+----------------------
+
+Memory usage for the UTXO cache is being calculated more accurately, so that
+the configured limit (`-dbcache`) will be respected when memory usage peaks
+during cache flushes. The memory accounting in prior releases is estimated to
+only account for half the actual peak utilization.
+
+The default `-dbcache` has also been changed in this release to 450MiB. Users
+who currently set `-dbcache` to a high value (e.g. to keep the UTXO more fully
+cached in memory) should consider increasing this setting in order to achieve
+the same cache performance as prior releases. Users on low-memory systems
+(such as systems with 1GB or less) should consider specifying a lower value for
+this parameter.
+
+Additional information relating to running on low-memory systems can be found
+here:
+[reducing-bitcoind-memory-usage.md](https://gist.github.com/laanwj/efe29c7661ce9b6620a7).
+
+0.14.1 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, refactors and string updates. For convenience in locating
+the code changes and accompanying discussion, both the pull request and
+git merge commit are mentioned.
+
+### RPC and other APIs
+- #10084 `142fbb2` Rename first named arg of createrawtransaction (MarcoFalke)
+- #10139 `f15268d` Remove auth cookie on shutdown (practicalswift)
+- #10146 `2fea10a` Better error handling for submitblock (rawodb, gmaxwell)
+- #10144 `d947afc` Prioritisetransaction wasn't always updating ancestor fee (sdaftuar)
+- #10204 `3c79602` Rename disconnectnode argument (jnewbery)
+
+### Block and transaction handling
+- #10126 `0b5e162` Compensate for memory peak at flush time (sipa)
+- #9912 `fc3d7db` Optimize GetWitnessHash() for non-segwit transactions (sdaftuar)
+- #10133 `ab864d3` Clean up calculations of pcoinsTip memory usage (morcos)
+
+### P2P protocol and network code
+- #9953/#10013 `d2548a4` Fix shutdown hang with >= 8 -addnodes set (TheBlueMatt)
+- #10176 `30fa231` net: gracefully handle NodeId wrapping (theuni)
+
+### Build system
+- #9973 `e9611d1` depends: fix zlib build on osx (theuni)
+
+### GUI
+- #10060 `ddc2dd1` Ensure an item exists on the rpcconsole stack before adding (achow101)
+
+### Mining
+- #9955/#10006 `569596c` Don't require segwit in getblocktemplate for segwit signalling or mining (sdaftuar)
+- #9959/#10127 `b5c3440` Prevent slowdown in CreateNewBlock on large mempools (sdaftuar)
+
+### Tests and QA
+- #10157 `55f641c` Fix the `mempool_packages.py` test (sdaftuar)
+
+### Miscellaneous
+- #10037 `4d8e660` Trivial: Fix typo in help getrawtransaction RPC (keystrike)
+- #10120 `e4c9a90` util: Work around (virtual) memory exhaustion on 32-bit w/ glibc (laanwj)
+- #10130 `ecc5232` bitcoin-tx input verification (awemany, jnewbery)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Alex Morcos
+- Andrew Chow
+- Awemany
+- Cory Fields
+- Gregory Maxwell
+- James Evans
+- John Newbery
+- MarcoFalke
+- Matt Corallo
+- Pieter Wuille
+- practicalswift
+- rawodb
+- Suhas Daftuar
+- Wladimir J. van der Laan
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
+
diff --git a/doc/release-process.md b/doc/release-process.md
index 35ee1edae1..5a99b726f1 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -5,18 +5,31 @@ Before every release candidate:
* Update translations (ping wumpus on IRC) see [translation_process.md](https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md#synchronising-translations).
+* Update manpages, see [gen-manpages.sh](https://github.com/bitcoin/bitcoin/blob/master/contrib/devtools/README.md#gen-manpagessh).
+
Before every minor and major release:
* Update [bips.md](bips.md) to account for changes since the last release.
-* Update version in sources (see below)
+* Update version in `configure.ac` (don't forget to set `CLIENT_VERSION_IS_RELEASE` to `true`)
* Write release notes (see below)
+* Update `src/chainparams.cpp` nMinimumChainWork with information from the getblockchaininfo rpc.
+* Update `src/chainparams.cpp` defaultAssumeValid with information from the getblockhash rpc.
+ - The selected value must not be orphaned so it may be useful to set the value two blocks back from the tip.
+ - Testnet should be set some tens of thousands back from the tip due to reorgs there.
+ - This update should be reviewed with a reindex-chainstate with assumevalid=0 to catch any defect
+ that causes rejection of blocks in the past history.
Before every major release:
* Update hardcoded [seeds](/contrib/seeds/README.md), see [this pull request](https://github.com/bitcoin/bitcoin/pull/7415) for an example.
+* Update [`BLOCK_CHAIN_SIZE`](/src/qt/intro.cpp) to the current size plus some overhead.
+* Update `src/chainparams.cpp` chainTxData with statistics about the transaction count and rate.
+* Update version of `contrib/gitian-descriptors/*.yml`: usually one'd want to do this on master after branching off the release - but be sure to at least do it before a new major release
### First time / New builders
+If you're using the automated script (found in [contrib/gitian-build.sh](/contrib/gitian-build.sh)), then at this point you should run it with the "--setup" command. Otherwise ignore this.
+
Check out the source code in the following directory hierarchy.
cd /path/to/your/toplevel/build
@@ -25,23 +38,7 @@ Check out the source code in the following directory hierarchy.
git clone https://github.com/devrandom/gitian-builder.git
git clone https://github.com/bitcoin/bitcoin.git
-### Bitcoin maintainers/release engineers, update version in sources
-
-Update the following:
-
-- `configure.ac`:
- - `_CLIENT_VERSION_MAJOR`
- - `_CLIENT_VERSION_MINOR`
- - `_CLIENT_VERSION_REVISION`
- - Don't forget to set `_CLIENT_VERSION_IS_RELEASE` to `true`
-- `src/clientversion.h`: (this mirrors `configure.ac` - see issue #3539)
- - `CLIENT_VERSION_MAJOR`
- - `CLIENT_VERSION_MINOR`
- - `CLIENT_VERSION_REVISION`
- - Don't forget to set `CLIENT_VERSION_IS_RELEASE` to `true`
-- `doc/README.md` and `doc/README_windows.txt`
-- `doc/Doxyfile`: `PROJECT_NUMBER` contains the full version
-- `contrib/gitian-descriptors/*.yml`: usually one'd want to do this on master after branching off the release - but be sure to at least do it before a new major release
+### Bitcoin maintainers/release engineers, suggestion for writing release notes
Write release notes. git shortlog helps a lot, for example:
@@ -60,6 +57,8 @@ Tag version (or release candidate) in git
### Setup and perform Gitian builds
+If you're using the automated script (found in [contrib/gitian-build.sh](/contrib/gitian-build.sh)), then at this point you should run it with the "--build" command. Otherwise ignore this.
+
Setup Gitian descriptors:
pushd ./bitcoin
@@ -112,16 +111,16 @@ The gbuild invocations below <b>DO NOT DO THIS</b> by default.
### Build and sign Bitcoin Core for Linux, Windows, and OS X:
pushd ./gitian-builder
- ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ ./bin/gbuild --memory 3000 --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
./bin/gsign --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../
- ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+ ./bin/gbuild --memory 3000 --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
./bin/gsign --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz
mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../
- ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
+ ./bin/gbuild --memory 3000 --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
./bin/gsign --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz
mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../
@@ -137,9 +136,10 @@ Build output expected:
### Verify other gitian builders signatures to your own. (Optional)
-Add other gitian builders keys to your gpg keyring
+Add other gitian builders keys to your gpg keyring, and/or refresh keys.
gpg --import bitcoin/contrib/gitian-keys/*.pgp
+ gpg --refresh-keys
Verify the signatures
@@ -161,7 +161,38 @@ Commit your signature to gitian.sigs:
git push # Assuming you can push to the gitian.sigs tree
popd
-Wait for Windows/OS X detached signatures:
+Codesigner only: Create Windows/OS X detached signatures:
+- Only one person handles codesigning. Everyone else should skip to the next step.
+- Only once the Windows/OS X builds each have 3 matching signatures may they be signed with their respective release keys.
+
+Codesigner only: Sign the osx binary:
+
+ transfer bitcoin-osx-unsigned.tar.gz to osx for signing
+ tar xf bitcoin-osx-unsigned.tar.gz
+ ./detached-sig-create.sh -s "Key ID"
+ Enter the keychain password and authorize the signature
+ Move signature-osx.tar.gz back to the gitian host
+
+Codesigner only: Sign the windows binaries:
+
+ tar xf bitcoin-win-unsigned.tar.gz
+ ./detached-sig-create.sh -key /path/to/codesign.key
+ Enter the passphrase for the key when prompted
+ signature-win.tar.gz will be created
+
+Codesigner only: Commit the detached codesign payloads:
+
+ cd ~/bitcoin-detached-sigs
+ checkout the appropriate branch for this release series
+ rm -rf *
+ tar xf signature-osx.tar.gz
+ tar xf signature-win.tar.gz
+ git add -a
+ git commit -m "point to ${VERSION}"
+ git tag -s v${VERSION} HEAD
+ git push the current branch and new tag
+
+Non-codesigners: wait for Windows/OS X detached signatures:
- Once the Windows/OS X builds each have 3 matching signatures, they will be signed with their respective release keys.
- Detached signatures will then be committed to the [bitcoin-detached-sigs](https://github.com/bitcoin-core/bitcoin-detached-sigs) repository, which can be combined with the unsigned apps to create signed binaries.
@@ -271,6 +302,8 @@ bitcoin.org (see below for bitcoin.org update instructions).
- Notify BlueMatt so that he can start building [the PPAs](https://launchpad.net/~bitcoin/+archive/ubuntu/bitcoin)
- - Add release notes for the new version to the directory `doc/release-notes` in git master
+ - Archive release notes for the new version to `doc/release-notes/` (branch `master` and branch of the release)
+
+ - Create a [new GitHub release](https://github.com/bitcoin/bitcoin/releases/new) with a link to the archived release notes.
- Celebrate
diff --git a/doc/shared-libraries.md b/doc/shared-libraries.md
index ec6f16c8aa..dc363582cc 100644
--- a/doc/shared-libraries.md
+++ b/doc/shared-libraries.md
@@ -30,12 +30,17 @@ The interface is defined in the C header `bitcoinconsensus.h` located in `src/s
- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE`
- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH` - Evaluate P2SH ([BIP16](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki)) subscripts
- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG` - Enforce strict DER ([BIP66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki)) compliance
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY` - Enforce NULLDUMMY ([BIP147](https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki))
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY` - Enable CHECKLOCKTIMEVERIFY ([BIP65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki))
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY` - Enable CHECKSEQUENCEVERIFY ([BIP112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki))
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS` - Enable WITNESS ([BIP141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki))
##### Errors
- `bitcoinconsensus_ERR_OK` - No errors with input parameters *(see the return value of `bitcoinconsensus_verify_script` for the verification status)*
- `bitcoinconsensus_ERR_TX_INDEX` - An invalid index for `txTo`
- `bitcoinconsensus_ERR_TX_SIZE_MISMATCH` - `txToLen` did not match with the size of `txTo`
- `bitcoinconsensus_ERR_DESERIALIZE` - An error deserializing `txTo`
+- `bitcoinconsensus_ERR_AMOUNT_REQUIRED` - Input amount is required if WITNESS is used
### Example Implementations
- [NBitcoin](https://github.com/NicolasDorier/NBitcoin/blob/master/NBitcoin/Script.cs#L814) (.NET Bindings)
diff --git a/doc/tor.md b/doc/tor.md
index 79f1563021..a05979fca8 100644
--- a/doc/tor.md
+++ b/doc/tor.md
@@ -99,10 +99,10 @@ This means that if Tor is running (and proper authentication has been configured
Bitcoin Core automatically creates a hidden service to listen on. This will positively
affect the number of available .onion nodes.
-This new feature is enabled by default if Bitcoin Core is listening, and
-a connection to Tor can be made. It can be configured with the `-listenonion`,
-`-torcontrol` and `-torpassword` settings. To show verbose debugging
-information, pass `-debug=tor`.
+This new feature is enabled by default if Bitcoin Core is listening (`-listen`), and
+requires a Tor connection to work. It can be explicitly disabled with `-listenonion=0`
+and, if not disabled, configured using the `-torcontrol` and `-torpassword` settings.
+To show verbose debugging information, pass `-debug=tor`.
Connecting to Tor's control socket API requires one of two authentication methods to be
configured. For cookie authentication the user running bitcoind must have write access
@@ -113,4 +113,13 @@ the user running bitcoind to the same group and setting permissions appropriatel
Debian-based systems the user running bitcoind can be added to the debian-tor group,
which has the appropriate permissions. An alternative authentication method is the use
of the `-torpassword` flag and a `hash-password` which can be enabled and specified in
-Tor configuration. \ No newline at end of file
+Tor configuration.
+
+4. Privacy recommendations
+---------------------------
+
+- Do not add anything but bitcoin ports to the hidden service created in section 2.
+ If you run a web service too, create a new hidden service for that.
+ Otherwise it is trivial to link them, which may reduce privacy. Hidden
+ services created automatically (as in section 3) always have only one port
+ open.
diff --git a/doc/translation_process.md b/doc/translation_process.md
index 310d560b36..1702637d53 100644
--- a/doc/translation_process.md
+++ b/doc/translation_process.md
@@ -4,9 +4,9 @@ Translations
The Bitcoin-Core project has been designed to support multiple localisations. This makes adding new phrases, and completely new languages easily achievable. For managing all application translations, Bitcoin-Core makes use of the Transifex online translation management tool.
### Helping to translate (using Transifex)
-Transifex is setup to monitor the Github repo for updates, and when code containing new translations is found, Transifex will process any changes. It may take several hours after a pull-request has been merged, to appear in the Transifex web interface.
+Transifex is setup to monitor the GitHub repo for updates, and when code containing new translations is found, Transifex will process any changes. It may take several hours after a pull-request has been merged, to appear in the Transifex web interface.
-Multiple language support is critical in assisting Bitcoin’s global adoption, and growth. One of Bitcoin’s greatest strengths is cross-boarder money transfers, any help making that easier is greatly appreciated.
+Multiple language support is critical in assisting Bitcoin’s global adoption, and growth. One of Bitcoin’s greatest strengths is cross-border money transfers, any help making that easier is greatly appreciated.
See the [Transifex Bitcoin project](https://www.transifex.com/projects/p/bitcoin/) to assist in translations. You should also join the translation mailing list for announcements - see details below.
@@ -32,7 +32,7 @@ QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
### Creating a pull-request
For general PRs, you shouldn’t include any updates to the translation source files. They will be updated periodically, primarily around pre-releases, allowing time for any new phrases to be translated before public releases. This is also important in avoiding translation related merge conflicts.
-When an updated source file is merged into the Github repo, Transifex will automatically detect it (although it can take several hours). Once processed, the new strings will show up as "Remaining" in the Transifex web interface and are ready for translators.
+When an updated source file is merged into the GitHub repo, Transifex will automatically detect it (although it can take several hours). Once processed, the new strings will show up as "Remaining" in the Transifex web interface and are ready for translators.
To create the pull-request, use the following commands:
```
@@ -94,7 +94,7 @@ When new plurals are added to the source file, it's important to do the followin
7. Save the source file
### Translating a new language
-To create a new language template, you will need to edit the languages manifest file `src/qt/bitcoin.qrc` and add a new entry. Below is an example of the english language entry.
+To create a new language template, you will need to edit the languages manifest file `src/qt/bitcoin_locale.qrc` and add a new entry. Below is an example of the English language entry.
```xml
<qresource prefix="/translations">
diff --git a/doc/travis-ci.txt b/doc/travis-ci.md
index 06410405d6..38085cec35 100644
--- a/doc/travis-ci.txt
+++ b/doc/travis-ci.md
@@ -1,5 +1,8 @@
+Travis CI
+=========
+
Support for using travis-ci has been added in order to automate pull-testing.
-See https://travis-ci.org/ for more info
+See [travis-ci.org](https://travis-ci.org/) for more info
This procedure is different than the pull-tester that came before it in a few
ways.
@@ -7,7 +10,7 @@ ways.
There is nothing to administer. This is a major feature as it means
that builds have no local state. Because there is no ability to login to the
builders to install packages (tools, dependencies, etc), the entire build
-procedure must instead be controlled by a declarative script (.travis.yml).
+procedure must instead be controlled by a declarative script `.travis.yml`.
This script declares each build configuration, creates virtual machines as
necessary, builds, then discards the virtual machines.
@@ -16,7 +19,7 @@ than a single pass/fail. This helps to catch build failures and logic errors
that present on platforms other than the ones the author has tested. This
matrix is defined in the build script and can be changed at any time.
-All builders use the dependency-generator in the depends dir, rather than
+All builders use the dependency-generator in the [depends dir](/depends), rather than
using apt-get to install build dependencies. This guarantees that the tester
is using the same versions as Gitian, so the build results are nearly identical
to what would be found in a final release. However, this also means that builds
diff --git a/doc/unit-tests.md b/doc/unit-tests.md
deleted file mode 100644
index afaece829c..0000000000
--- a/doc/unit-tests.md
+++ /dev/null
@@ -1,18 +0,0 @@
-Compiling/running unit tests
-------------------------------------
-
-Unit tests will be automatically compiled if dependencies were met in `./configure`
-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 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
-implement new BOOST_AUTO_TEST_SUITE sections.
-
-To run the bitcoin-qt tests manually, launch `src/qt/test/test_bitcoin-qt`
-
-To add more bitcoin-qt tests, add them to the `src/qt/test/` directory and
-the `src/qt/test/test_main.cpp` file.
diff --git a/doc/zmq.md b/doc/zmq.md
index 6079e3254f..1019ff6653 100644
--- a/doc/zmq.md
+++ b/doc/zmq.md
@@ -1,4 +1,4 @@
-# Block and Transaction Broadcasting With ZeroMQ
+# Block and Transaction Broadcasting with ZeroMQ
[ZeroMQ](http://zeromq.org/) is a lightweight wrapper around TCP
connections, inter-process communication, and shared-memory,
@@ -50,7 +50,7 @@ during the *configure* step of building bitcoind:
$ ./configure --disable-zmq (other options)
To actually enable operation, one must set the appropriate options on
-the commandline or in the configuration file.
+the command line or in the configuration file.
## Usage
diff --git a/qa/README.md b/qa/README.md
deleted file mode 100644
index 723660c6c8..0000000000
--- a/qa/README.md
+++ /dev/null
@@ -1,87 +0,0 @@
-The [pull-tester](/qa/pull-tester/) folder contains a script to call
-multiple tests from the [rpc-tests](/qa/rpc-tests/) folder.
-
-Every pull request to the bitcoin repository is built and run through
-the regression test suite. You can also run all or only individual
-tests locally.
-
-Test dependencies
-=================
-Before running the tests, the following must be installed.
-
-Unix
-----
-The python3-zmq library is required. On Ubuntu or Debian it can be installed via:
-```
-sudo apt-get install python3-zmq
-```
-
-OS X
-------
-```
-pip3 install pyzmq
-```
-
-Running tests
-=============
-
-You can run any single test by calling
-
- qa/pull-tester/rpc-tests.py <testname>
-
-Or you can run any combination of tests by calling
-
- qa/pull-tester/rpc-tests.py <testname1> <testname2> <testname3> ...
-
-Run the regression test suite with
-
- qa/pull-tester/rpc-tests.py
-
-Run all possible tests with
-
- qa/pull-tester/rpc-tests.py -extended
-
-By default, tests will be run in parallel if you want to specify how many
-tests should be run in parallel, append `-parallel=n` (default n=4).
-
-If you want to create a basic coverage report for the rpc test suite, append `--coverage`.
-
-Possible options, which apply to each individual test run:
-
-```
- -h, --help show this help message and exit
- --nocleanup Leave bitcoinds and test.* datadir on exit or error
- --noshutdown Don't stop bitcoinds after the test execution
- --srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli
- (default: ../../src)
- --tmpdir=TMPDIR Root directory for datadirs
- --tracerpc Print out all RPC calls as they are made
- --coveragedir=COVERAGEDIR
- Write tested RPC commands into this directory
-```
-
-If you set the environment variable `PYTHON_DEBUG=1` you will get some debug
-output (example: `PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.py wallet`).
-
-A 200-block -regtest blockchain and wallets for four nodes
-is created the first time a regression test is run and
-is stored in the cache/ directory. Each node has 25 mature
-blocks (25*50=1250 BTC) in its wallet.
-
-After the first run, the cache/ blockchain and wallets are
-copied into a temporary directory and used as the initial
-test state.
-
-If you get into a bad state, you should be able
-to recover with:
-
-```bash
-rm -rf cache
-killall bitcoind
-```
-
-Writing tests
-=============
-You are encouraged to write tests for new or existing features.
-Further information about the test framework and individual rpc
-tests is found in [qa/rpc-tests](/qa/rpc-tests).
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
deleted file mode 100755
index 11b83bac14..0000000000
--- a/qa/pull-tester/rpc-tests.py
+++ /dev/null
@@ -1,341 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-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.
-
-"""
-Run Regression Test Suite
-
-This module calls down into individual test cases via subprocess. It will
-forward all unrecognized arguments onto the individual test scripts, other
-than:
-
- - `-extended`: run the "extended" test suite in addition to the basic one.
- - `-win`: signal that this is running in a Windows environment, and we
- should run the tests.
- - `--coverage`: this generates a basic coverage report for the RPC
- interface.
-
-For a description of arguments recognized by test scripts, see
-`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`.
-
-"""
-
-import os
-import time
-import shutil
-import sys
-import subprocess
-import tempfile
-import re
-
-sys.path.append("qa/pull-tester/")
-from tests_config import *
-
-BOLD = ("","")
-if os.name == 'posix':
- # primitive formatting on supported
- # terminal via ANSI escape sequences:
- BOLD = ('\033[0m', '\033[1m')
-
-RPC_TESTS_DIR = SRCDIR + '/qa/rpc-tests/'
-
-#If imported values are not defined then set to zero (or disabled)
-if 'ENABLE_WALLET' not in vars():
- ENABLE_WALLET=0
-if 'ENABLE_BITCOIND' not in vars():
- ENABLE_BITCOIND=0
-if 'ENABLE_UTILS' not in vars():
- ENABLE_UTILS=0
-if 'ENABLE_ZMQ' not in vars():
- ENABLE_ZMQ=0
-
-ENABLE_COVERAGE=0
-
-#Create a set to store arguments and create the passon string
-opts = set()
-passon_args = []
-PASSON_REGEX = re.compile("^--")
-PARALLEL_REGEX = re.compile('^-parallel=')
-
-print_help = False
-run_parallel = 4
-
-for arg in sys.argv[1:]:
- if arg == "--help" or arg == "-h" or arg == "-?":
- print_help = True
- break
- if arg == '--coverage':
- ENABLE_COVERAGE = 1
- elif PASSON_REGEX.match(arg):
- passon_args.append(arg)
- elif PARALLEL_REGEX.match(arg):
- run_parallel = int(arg.split(sep='=', maxsplit=1)[1])
- else:
- opts.add(arg)
-
-#Set env vars
-if "BITCOIND" not in os.environ:
- os.environ["BITCOIND"] = BUILDDIR + '/src/bitcoind' + EXEEXT
-if "BITCOINCLI" not in os.environ:
- os.environ["BITCOINCLI"] = BUILDDIR + '/src/bitcoin-cli' + EXEEXT
-
-if EXEEXT == ".exe" and "-win" not in opts:
- # https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
- # https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
- print("Win tests currently disabled by default. Use -win option to enable")
- sys.exit(0)
-
-if not (ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
- print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled")
- sys.exit(0)
-
-# python3-zmq may not be installed. Handle this gracefully and with some helpful info
-if ENABLE_ZMQ:
- try:
- import zmq
- except ImportError as e:
- print("WARNING: \"import zmq\" failed. Set ENABLE_ZMQ=0 or " \
- "to run zmq tests, see dependency info in /qa/README.md.")
- ENABLE_ZMQ=0
-
-#Tests
-testScripts = [
- # longest test should go first, to favor running tests in parallel
- 'p2p-fullblocktest.py',
- 'walletbackup.py',
- 'bip68-112-113-p2p.py',
- 'wallet.py',
- 'wallet-hd.py',
- 'listtransactions.py',
- 'receivedby.py',
- 'mempool_resurrect_test.py',
- 'txn_doublespend.py --mineblock',
- 'txn_clone.py',
- 'getchaintips.py',
- 'rawtransactions.py',
- 'rest.py',
- 'mempool_spendcoinbase.py',
- 'mempool_reorg.py',
- 'mempool_limit.py',
- 'httpbasics.py',
- 'multi_rpc.py',
- 'zapwallettxes.py',
- 'proxy_test.py',
- 'merkle_blocks.py',
- 'fundrawtransaction.py',
- 'signrawtransactions.py',
- 'nodehandling.py',
- 'reindex.py',
- 'decodescript.py',
- 'blockchain.py',
- 'disablewallet.py',
- 'sendheaders.py',
- 'keypool.py',
- 'prioritise_transaction.py',
- 'invalidblockrequest.py',
- 'invalidtxrequest.py',
- 'abandonconflict.py',
- 'p2p-versionbits-warning.py',
- 'p2p-segwit.py',
- 'segwit.py',
- 'importprunedfunds.py',
- 'signmessages.py',
-]
-if ENABLE_ZMQ:
- testScripts.append('zmq_test.py')
-
-testScriptsExt = [
- 'bip9-softforks.py',
- 'bip65-cltv.py',
- 'bip65-cltv-p2p.py',
- 'bip68-sequence.py',
- 'bipdersig-p2p.py',
- 'bipdersig.py',
- 'getblocktemplate_longpoll.py',
- 'getblocktemplate_proposals.py',
- 'txn_doublespend.py',
- 'txn_clone.py --mineblock',
- 'forknotify.py',
- 'invalidateblock.py',
-# 'rpcbind_test.py', #temporary, bug in libevent, see #6655
- 'smartfees.py',
- 'maxblocksinflight.py',
- 'p2p-acceptblock.py',
- 'mempool_packages.py',
- 'maxuploadtarget.py',
- 'replace-by-fee.py',
- 'p2p-feefilter.py',
- 'pruning.py', # leave pruning last as it takes a REALLY long time
-]
-
-
-def runtests():
- test_list = []
- if '-extended' in opts:
- test_list = testScripts + testScriptsExt
- elif len(opts) == 0 or (len(opts) == 1 and "-win" in opts):
- test_list = testScripts
- else:
- for t in testScripts + testScriptsExt:
- if t in opts or re.sub(".py$", "", t) in opts:
- test_list.append(t)
-
- if print_help:
- # Only print help of the first script and exit
- subprocess.check_call((RPC_TESTS_DIR + test_list[0]).split() + ['-h'])
- sys.exit(0)
-
- coverage = None
-
- if ENABLE_COVERAGE:
- coverage = RPCCoverage()
- print("Initializing coverage directory at %s\n" % coverage.dir)
- flags = ["--srcdir=%s/src" % BUILDDIR] + passon_args
- if coverage:
- flags.append(coverage.flag)
-
- if len(test_list) > 1 and run_parallel > 1:
- # Populate cache
- subprocess.check_output([RPC_TESTS_DIR + 'create_cache.py'] + flags)
-
- #Run Tests
- max_len_name = len(max(test_list, key=len))
- time_sum = 0
- time0 = time.time()
- job_queue = RPCTestHandler(run_parallel, test_list, flags)
- results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "PASSED", "DURATION") + BOLD[0]
- all_passed = True
- for _ in range(len(test_list)):
- (name, stdout, stderr, passed, duration) = job_queue.get_next()
- all_passed = all_passed and passed
- time_sum += duration
-
- print('\n' + BOLD[1] + name + BOLD[0] + ":")
- print(stdout)
- print('stderr:\n' if not stderr == '' else '', stderr)
- results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration)
- print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration))
- results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0]
- print(results)
- print("\nRuntime: %s s" % (int(time.time() - time0)))
-
- if coverage:
- coverage.report_rpc_coverage()
-
- print("Cleaning up coverage data")
- coverage.cleanup()
-
- sys.exit(not all_passed)
-
-
-class RPCTestHandler:
- """
- Trigger the testscrips passed in via the list.
- """
-
- def __init__(self, num_tests_parallel, test_list=None, flags=None):
- assert(num_tests_parallel >= 1)
- self.num_jobs = num_tests_parallel
- self.test_list = test_list
- self.flags = flags
- self.num_running = 0
- self.jobs = []
-
- def get_next(self):
- while self.num_running < self.num_jobs and self.test_list:
- # Add tests
- self.num_running += 1
- t = self.test_list.pop(0)
- port_seed = ["--portseed=%s" % len(self.test_list)]
- self.jobs.append((t,
- time.time(),
- subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags + port_seed,
- universal_newlines=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)))
- if not self.jobs:
- raise IndexError('pop from empty list')
- while True:
- # Return first proc that finishes
- time.sleep(.5)
- for j in self.jobs:
- (name, time0, proc) = j
- if proc.poll() is not None:
- (stdout, stderr) = proc.communicate(timeout=3)
- passed = stderr == "" and proc.returncode == 0
- self.num_running -= 1
- self.jobs.remove(j)
- return name, stdout, stderr, passed, int(time.time() - time0)
- print('.', end='', flush=True)
-
-
-class RPCCoverage(object):
- """
- Coverage reporting utilities for pull-tester.
-
- Coverage calculation works by having each test script subprocess write
- coverage files into a particular directory. These files contain the RPC
- commands invoked during testing, as well as a complete listing of RPC
- commands per `bitcoin-cli help` (`rpc_interface.txt`).
-
- After all tests complete, the commands run are combined and diff'd against
- the complete list to calculate uncovered RPC commands.
-
- See also: qa/rpc-tests/test_framework/coverage.py
-
- """
- def __init__(self):
- self.dir = tempfile.mkdtemp(prefix="coverage")
- self.flag = '--coveragedir=%s' % self.dir
-
- def report_rpc_coverage(self):
- """
- Print out RPC commands that were unexercised by tests.
-
- """
- uncovered = self._get_uncovered_rpc_commands()
-
- if uncovered:
- print("Uncovered RPC commands:")
- print("".join((" - %s\n" % i) for i in sorted(uncovered)))
- else:
- print("All RPC commands covered.")
-
- def cleanup(self):
- return shutil.rmtree(self.dir)
-
- def _get_uncovered_rpc_commands(self):
- """
- Return a set of currently untested RPC commands.
-
- """
- # This is shared from `qa/rpc-tests/test-framework/coverage.py`
- REFERENCE_FILENAME = 'rpc_interface.txt'
- COVERAGE_FILE_PREFIX = 'coverage.'
-
- coverage_ref_filename = os.path.join(self.dir, REFERENCE_FILENAME)
- coverage_filenames = set()
- all_cmds = set()
- covered_cmds = set()
-
- if not os.path.isfile(coverage_ref_filename):
- raise RuntimeError("No coverage reference found")
-
- with open(coverage_ref_filename, 'r') as f:
- all_cmds.update([i.strip() for i in f.readlines()])
-
- for root, dirs, files in os.walk(self.dir):
- for filename in files:
- if filename.startswith(COVERAGE_FILE_PREFIX):
- coverage_filenames.add(os.path.join(root, filename))
-
- for filename in coverage_filenames:
- with open(filename, 'r') as f:
- covered_cmds.update([i.strip() for i in f.readlines()])
-
- return all_cmds - covered_cmds
-
-
-if __name__ == '__main__':
- runtests()
diff --git a/qa/pull-tester/run-bitcoind-for-test.sh.in b/qa/pull-tester/run-bitcoind-for-test.sh.in
deleted file mode 100644
index 14ae08e4e5..0000000000
--- a/qa/pull-tester/run-bitcoind-for-test.sh.in
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2013-2014 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-DATADIR="@abs_top_builddir@/.bitcoin"
-rm -rf "$DATADIR"
-mkdir -p "$DATADIR"/regtest
-touch "$DATADIR/regtest/debug.log"
-tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" &
-WAITER=$!
-PORT=`expr 10000 + $$ % 55536`
-"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -checkmempool=0 -relaypriority=0 -port=$PORT -whitelist=127.0.0.1 -regtest -rpcport=`expr $PORT + 1` &
-BITCOIND=$!
-
-#Install a watchdog.
-(sleep 10 && kill -0 $WAITER 2>/dev/null && kill -9 $BITCOIND $$)&
-wait $WAITER
-
-if [ -n "$TIMEOUT" ]; then
- timeout "$TIMEOUT"s "$@" $PORT
- RETURN=$?
-else
- "$@" $PORT
- RETURN=$?
-fi
-
-(sleep 15 && kill -0 $BITCOIND 2>/dev/null && kill -9 $BITCOIND $$)&
-kill $BITCOIND && wait $BITCOIND
-
-# timeout returns 124 on timeout, otherwise the return value of the child
-
-# If $RETURN is not 0, the test failed. Dump the tail of the debug log.
-if [ $RETURN -ne 0 ]; then tail -n 200 $DATADIR/regtest/debug.log; fi
-
-exit $RETURN
diff --git a/qa/pull-tester/tests_config.py.in b/qa/pull-tester/tests_config.py.in
deleted file mode 100644
index a0d0a3d98a..0000000000
--- a/qa/pull-tester/tests_config.py.in
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2013-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.
-
-SRCDIR="@abs_top_srcdir@"
-BUILDDIR="@abs_top_builddir@"
-EXEEXT="@EXEEXT@"
-
-# These will turn into comments if they were disabled when configuring.
-@ENABLE_WALLET_TRUE@ENABLE_WALLET=1
-@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=1
-@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=1
-@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=1
diff --git a/qa/rpc-tests/disablewallet.py b/qa/rpc-tests/disablewallet.py
deleted file mode 100755
index 36c147edad..0000000000
--- a/qa/rpc-tests/disablewallet.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2015-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.
-
-#
-# Exercise API with -disablewallet.
-#
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-
-
-class DisableWalletTest (BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = True
- self.num_nodes = 1
-
- def setup_network(self, split=False):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [['-disablewallet']])
- self.is_network_split = False
- self.sync_all()
-
- def run_test (self):
- # Check regression: https://github.com/bitcoin/bitcoin/issues/6963#issuecomment-154548880
- x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
- assert(x['isvalid'] == False)
- x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
- assert(x['isvalid'] == True)
-
- # Checking mining to an address without a wallet
- try:
- self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
- except JSONRPCException as e:
- assert("Invalid address" not in e.error['message'])
- assert("ProcessNewBlock, block not accepted" not in e.error['message'])
- assert("Couldn't create new block" not in e.error['message'])
-
- try:
- self.nodes[0].generatetoaddress(1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
- raise AssertionError("Must not mine to invalid address!")
- except JSONRPCException as e:
- assert("Invalid address" in e.error['message'])
-
-if __name__ == '__main__':
- DisableWalletTest ().main ()
diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py
deleted file mode 100755
index c75303ecbf..0000000000
--- a/qa/rpc-tests/keypool.py
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-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.
-
-# Exercise the wallet keypool, and interaction with wallet encryption/locking
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-
-class KeyPoolTest(BitcoinTestFramework):
-
- def run_test(self):
- nodes = self.nodes
- # Encrypt wallet and wait to terminate
- nodes[0].encryptwallet('test')
- bitcoind_processes[0].wait()
- # Restart node 0
- nodes[0] = start_node(0, self.options.tmpdir)
- # Keep creating keys
- addr = nodes[0].getnewaddress()
- try:
- addr = nodes[0].getnewaddress()
- raise AssertionError('Keypool should be exhausted after one address')
- except JSONRPCException as e:
- assert(e.error['code']==-12)
-
- # put three new keys in the keypool
- nodes[0].walletpassphrase('test', 12000)
- nodes[0].keypoolrefill(3)
- nodes[0].walletlock()
-
- # drain the keys
- addr = set()
- addr.add(nodes[0].getrawchangeaddress())
- addr.add(nodes[0].getrawchangeaddress())
- addr.add(nodes[0].getrawchangeaddress())
- addr.add(nodes[0].getrawchangeaddress())
- # assert that four unique addresses were returned
- assert(len(addr) == 4)
- # the next one should fail
- try:
- addr = nodes[0].getrawchangeaddress()
- raise AssertionError('Keypool should be exhausted after three addresses')
- except JSONRPCException as e:
- assert(e.error['code']==-12)
-
- # refill keypool with three new addresses
- nodes[0].walletpassphrase('test', 1)
- nodes[0].keypoolrefill(3)
- # test walletpassphrase timeout
- time.sleep(1.1)
- assert_equal(nodes[0].getwalletinfo()["unlocked_until"], 0)
-
- # drain them by mining
- nodes[0].generate(1)
- nodes[0].generate(1)
- nodes[0].generate(1)
- nodes[0].generate(1)
- try:
- nodes[0].generate(1)
- raise AssertionError('Keypool should be exhausted after three addesses')
- except JSONRPCException as e:
- assert(e.error['code']==-12)
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = False
- self.num_nodes = 1
-
- def setup_network(self):
- self.nodes = self.setup_nodes()
-
-if __name__ == '__main__':
- KeyPoolTest().main()
diff --git a/qa/rpc-tests/maxblocksinflight.py b/qa/rpc-tests/maxblocksinflight.py
deleted file mode 100755
index 1df1c484be..0000000000
--- a/qa/rpc-tests/maxblocksinflight.py
+++ /dev/null
@@ -1,96 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2015-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 test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-import logging
-
-'''
-In this test we connect to one node over p2p, send it numerous inv's, and
-compare the resulting number of getdata requests to a max allowed value. We
-test for exceeding 128 blocks in flight, which was the limit an 0.9 client will
-reach. [0.10 clients shouldn't request more than 16 from a single peer.]
-'''
-MAX_REQUESTS = 128
-
-class TestManager(NodeConnCB):
- # set up NodeConnCB callbacks, overriding base class
- def on_getdata(self, conn, message):
- self.log.debug("got getdata %s" % repr(message))
- # Log the requests
- for inv in message.inv:
- if inv.hash not in self.blockReqCounts:
- self.blockReqCounts[inv.hash] = 0
- self.blockReqCounts[inv.hash] += 1
-
- def on_close(self, conn):
- if not self.disconnectOkay:
- raise EarlyDisconnectError(0)
-
- def __init__(self):
- NodeConnCB.__init__(self)
- self.log = logging.getLogger("BlockRelayTest")
-
- def add_new_connection(self, connection):
- self.connection = connection
- self.blockReqCounts = {}
- self.disconnectOkay = False
-
- def run(self):
- self.connection.rpc.generate(1) # Leave IBD
-
- numBlocksToGenerate = [8, 16, 128, 1024]
- for count in range(len(numBlocksToGenerate)):
- current_invs = []
- for i in range(numBlocksToGenerate[count]):
- current_invs.append(CInv(2, random.randrange(0, 1 << 256)))
- if len(current_invs) >= 50000:
- self.connection.send_message(msg_inv(current_invs))
- current_invs = []
- if len(current_invs) > 0:
- self.connection.send_message(msg_inv(current_invs))
-
- # Wait and see how many blocks were requested
- time.sleep(2)
-
- total_requests = 0
- with mininode_lock:
- for key in self.blockReqCounts:
- total_requests += self.blockReqCounts[key]
- if self.blockReqCounts[key] > 1:
- raise AssertionError("Error, test failed: block %064x requested more than once" % key)
- if total_requests > MAX_REQUESTS:
- raise AssertionError("Error, too many blocks (%d) requested" % total_requests)
- print("Round %d: success (total requests: %d)" % (count, total_requests))
-
- self.disconnectOkay = True
- self.connection.disconnect_node()
-
-
-class MaxBlocksInFlightTest(BitcoinTestFramework):
- def add_options(self, parser):
- parser.add_option("--testbinary", dest="testbinary",
- default=os.getenv("BITCOIND", "bitcoind"),
- help="Binary to test max block requests behavior")
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = True
- self.num_nodes = 1
-
- def setup_network(self):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1']],
- binary=[self.options.testbinary])
-
- def run_test(self):
- test = TestManager()
- test.add_new_connection(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test))
- NetworkThread().start() # Start up network handling in another thread
- test.run()
-
-if __name__ == '__main__':
- MaxBlocksInFlightTest().main()
diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py
deleted file mode 100755
index e9682c4908..0000000000
--- a/qa/rpc-tests/nodehandling.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-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.
-
-#
-# Test node handling
-#
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-
-import http.client
-import urllib.parse
-
-class NodeHandlingTest (BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.num_nodes = 4
- self.setup_clean_chain = False
-
- def run_test(self):
- ###########################
- # setban/listbanned tests #
- ###########################
- assert_equal(len(self.nodes[2].getpeerinfo()), 4) #we should have 4 nodes at this point
- self.nodes[2].setban("127.0.0.1", "add")
- time.sleep(3) #wait till the nodes are disconected
- assert_equal(len(self.nodes[2].getpeerinfo()), 0) #all nodes must be disconnected at this point
- assert_equal(len(self.nodes[2].listbanned()), 1)
- self.nodes[2].clearbanned()
- assert_equal(len(self.nodes[2].listbanned()), 0)
- self.nodes[2].setban("127.0.0.0/24", "add")
- assert_equal(len(self.nodes[2].listbanned()), 1)
- try:
- self.nodes[2].setban("127.0.0.1", "add") #throws exception because 127.0.0.1 is within range 127.0.0.0/24
- except:
- pass
- assert_equal(len(self.nodes[2].listbanned()), 1) #still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24
- try:
- self.nodes[2].setban("127.0.0.1", "remove")
- except:
- pass
- assert_equal(len(self.nodes[2].listbanned()), 1)
- self.nodes[2].setban("127.0.0.0/24", "remove")
- assert_equal(len(self.nodes[2].listbanned()), 0)
- self.nodes[2].clearbanned()
- assert_equal(len(self.nodes[2].listbanned()), 0)
-
- ##test persisted banlist
- self.nodes[2].setban("127.0.0.0/32", "add")
- self.nodes[2].setban("127.0.0.0/24", "add")
- self.nodes[2].setban("192.168.0.1", "add", 1) #ban for 1 seconds
- self.nodes[2].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) #ban for 1000 seconds
- listBeforeShutdown = self.nodes[2].listbanned()
- assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) #must be here
- time.sleep(2) #make 100% sure we expired 192.168.0.1 node time
-
- #stop node
- stop_node(self.nodes[2], 2)
-
- self.nodes[2] = start_node(2, self.options.tmpdir)
- listAfterShutdown = self.nodes[2].listbanned()
- assert_equal("127.0.0.0/24", listAfterShutdown[0]['address'])
- assert_equal("127.0.0.0/32", listAfterShutdown[1]['address'])
- assert_equal("/19" in listAfterShutdown[2]['address'], True)
-
- ###########################
- # RPC disconnectnode test #
- ###########################
- url = urllib.parse.urlparse(self.nodes[1].url)
- self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1)))
- time.sleep(2) #disconnecting a node needs a little bit of time
- for node in self.nodes[0].getpeerinfo():
- assert(node['addr'] != url.hostname+":"+str(p2p_port(1)))
-
- connect_nodes_bi(self.nodes,0,1) #reconnect the node
- found = False
- for node in self.nodes[0].getpeerinfo():
- if node['addr'] == url.hostname+":"+str(p2p_port(1)):
- found = True
- assert(found)
-
-if __name__ == '__main__':
- NodeHandlingTest ().main ()
diff --git a/qa/rpc-tests/p2p-mempool.py b/qa/rpc-tests/p2p-mempool.py
deleted file mode 100755
index 5d2daf39f8..0000000000
--- a/qa/rpc-tests/p2p-mempool.py
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2015-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 test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-import time
-
-class TestNode(NodeConnCB):
- def __init__(self):
- NodeConnCB.__init__(self)
- self.connection = None
- self.ping_counter = 1
- self.last_pong = msg_pong()
- self.block_receive_map = {}
-
- def add_connection(self, conn):
- self.connection = conn
- self.peer_disconnected = False
-
- def on_inv(self, conn, message):
- pass
-
- # Track the last getdata message we receive (used in the test)
- def on_getdata(self, conn, message):
- self.last_getdata = message
-
- def on_block(self, conn, message):
- message.block.calc_sha256()
- try:
- self.block_receive_map[message.block.sha256] += 1
- except KeyError as e:
- self.block_receive_map[message.block.sha256] = 1
-
- # Spin until verack message is received from the node.
- # We use this to signal that our test can begin. This
- # is called from the testing thread, so it needs to acquire
- # the global lock.
- def wait_for_verack(self):
- def veracked():
- return self.verack_received
- return wait_until(veracked, timeout=10)
-
- def wait_for_disconnect(self):
- def disconnected():
- return self.peer_disconnected
- return wait_until(disconnected, timeout=10)
-
- # Wrapper for the NodeConn's send_message function
- def send_message(self, message):
- self.connection.send_message(message)
-
- def on_pong(self, conn, message):
- self.last_pong = message
-
- def on_close(self, conn):
- self.peer_disconnected = True
-
- # Sync up with the node after delivery of a block
- def sync_with_ping(self, timeout=30):
- def received_pong():
- return (self.last_pong.nonce == self.ping_counter)
- self.connection.send_message(msg_ping(nonce=self.ping_counter))
- success = wait_until(received_pong, timeout)
- self.ping_counter += 1
- return success
-
- def send_mempool(self):
- self.lastInv = []
- self.send_message(msg_mempool())
-
-class P2PMempoolTests(BitcoinTestFramework):
- def setup_chain(self):
- initialize_chain_clean(self.options.tmpdir, 2)
-
- def setup_network(self):
- # Start a node with maxuploadtarget of 200 MB (/24h)
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-peerbloomfilters=0"]))
-
- def run_test(self):
- #connect a mininode
- aTestNode = TestNode()
- node = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], aTestNode)
- aTestNode.add_connection(node)
- NetworkThread().start()
- aTestNode.wait_for_verack()
-
- #request mempool
- aTestNode.send_mempool()
- aTestNode.wait_for_disconnect()
-
- #mininode must be disconnected at this point
- assert_equal(len(self.nodes[0].getpeerinfo()), 0)
-
-if __name__ == '__main__':
- P2PMempoolTests().main()
diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py
deleted file mode 100755
index 572273566b..0000000000
--- a/qa/rpc-tests/rpcbind_test.py
+++ /dev/null
@@ -1,147 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-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.
-
-# Test for -rpcbind, as well as -rpcallowip and -rpcconnect
-
-# TODO extend this test from the test framework (like all other tests)
-
-import tempfile
-import traceback
-
-from test_framework.util import *
-from test_framework.netutil import *
-
-def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected):
- '''
- Start a node with requested rpcallowip and rpcbind parameters,
- then try to connect, and check if the set of bound addresses
- matches the expected set.
- '''
- expected = [(addr_to_hex(addr), port) for (addr, port) in expected]
- base_args = ['-disablewallet', '-nolisten']
- if allow_ips:
- base_args += ['-rpcallowip=' + x for x in allow_ips]
- binds = ['-rpcbind='+addr for addr in addresses]
- nodes = start_nodes(self.num_nodes, tmpdir, [base_args + binds], connect_to)
- try:
- pid = bitcoind_processes[0].pid
- assert_equal(set(get_bind_addrs(pid)), set(expected))
- finally:
- stop_nodes(nodes)
- wait_bitcoinds()
-
-def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport):
- '''
- Start a node with rpcwallow IP, and request getinfo
- at a non-localhost IP.
- '''
- base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
- nodes = start_nodes(self.num_nodes, tmpdir, [base_args])
- try:
- # connect to node through non-loopback interface
- url = "http://rt:rt@%s:%d" % (rpchost, rpcport,)
- node = get_rpc_proxy(url, 1)
- node.getinfo()
- finally:
- node = None # make sure connection will be garbage collected and closed
- stop_nodes(nodes)
- wait_bitcoinds()
-
-
-def run_test(tmpdir):
- assert(sys.platform.startswith('linux')) # due to OS-specific network stats queries, this test works only on Linux
- # find the first non-loopback interface for testing
- non_loopback_ip = None
- for name,ip in all_interfaces():
- if ip != '127.0.0.1':
- non_loopback_ip = ip
- break
- if non_loopback_ip is None:
- assert(not 'This test requires at least one non-loopback IPv4 interface')
- print("Using interface %s for testing" % non_loopback_ip)
-
- defaultport = rpc_port(0)
-
- # check default without rpcallowip (IPv4 and IPv6 localhost)
- run_bind_test(tmpdir, None, '127.0.0.1', [],
- [('127.0.0.1', defaultport), ('::1', defaultport)])
- # check default with rpcallowip (IPv6 any)
- run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', [],
- [('::0', defaultport)])
- # check only IPv4 localhost (explicit)
- run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', ['127.0.0.1'],
- [('127.0.0.1', defaultport)])
- # check only IPv4 localhost (explicit) with alternative port
- run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171'],
- [('127.0.0.1', 32171)])
- # check only IPv4 localhost (explicit) with multiple alternative ports on same host
- run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171', '127.0.0.1:32172'],
- [('127.0.0.1', 32171), ('127.0.0.1', 32172)])
- # check only IPv6 localhost (explicit)
- run_bind_test(tmpdir, ['[::1]'], '[::1]', ['[::1]'],
- [('::1', defaultport)])
- # check both IPv4 and IPv6 localhost (explicit)
- run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', ['127.0.0.1', '[::1]'],
- [('127.0.0.1', defaultport), ('::1', defaultport)])
- # check only non-loopback interface
- run_bind_test(tmpdir, [non_loopback_ip], non_loopback_ip, [non_loopback_ip],
- [(non_loopback_ip, defaultport)])
-
- # Check that with invalid rpcallowip, we are denied
- run_allowip_test(tmpdir, [non_loopback_ip], non_loopback_ip, defaultport)
- try:
- run_allowip_test(tmpdir, ['1.1.1.1'], non_loopback_ip, defaultport)
- assert(not 'Connection not denied by rpcallowip as expected')
- except ValueError:
- pass
-
-def main():
- import optparse
-
- parser = optparse.OptionParser(usage="%prog [options]")
- parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
- help="Leave bitcoinds and test.* datadir on exit or error")
- parser.add_option("--srcdir", dest="srcdir", default="../../src",
- help="Source directory containing bitcoind/bitcoin-cli (default: %default%)")
- parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
- help="Root directory for datadirs")
- (options, args) = parser.parse_args()
-
- os.environ['PATH'] = options.srcdir+":"+os.environ['PATH']
-
- check_json_precision()
-
- success = False
- nodes = []
- try:
- print("Initializing test directory "+options.tmpdir)
- if not os.path.isdir(options.tmpdir):
- os.makedirs(options.tmpdir)
- initialize_chain(options.tmpdir)
-
- run_test(options.tmpdir)
-
- success = True
-
- except AssertionError as e:
- print("Assertion failed: "+e.message)
- except Exception as e:
- print("Unexpected exception caught during testing: "+str(e))
- traceback.print_tb(sys.exc_info()[2])
-
- if not options.nocleanup:
- print("Cleaning up")
- wait_bitcoinds()
- shutil.rmtree(options.tmpdir)
-
- if success:
- print("Tests successful")
- sys.exit(0)
- else:
- print("Failed")
- sys.exit(1)
-
-if __name__ == '__main__':
- main()
diff --git a/qa/rpc-tests/segwit.py b/qa/rpc-tests/segwit.py
deleted file mode 100755
index d4c9a8afed..0000000000
--- a/qa/rpc-tests/segwit.py
+++ /dev/null
@@ -1,209 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 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.
-
-#
-# Test the SegWit changeover logic
-#
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.mininode import sha256, ripemd160
-import os
-import shutil
-
-NODE_0 = 0
-NODE_1 = 1
-NODE_2 = 2
-WIT_V0 = 0
-WIT_V1 = 1
-
-def witness_script(version, pubkey):
- if (version == 0):
- pubkeyhash = bytes_to_hex_str(ripemd160(sha256(hex_str_to_bytes(pubkey))))
- pkscript = "0014" + pubkeyhash
- elif (version == 1):
- # 1-of-1 multisig
- scripthash = bytes_to_hex_str(sha256(hex_str_to_bytes("5121" + pubkey + "51ae")))
- pkscript = "0020" + scripthash
- else:
- assert("Wrong version" == "0 or 1")
- return pkscript
-
-def addlength(script):
- scriptlen = format(len(script)//2, 'x')
- assert(len(scriptlen) == 2)
- return scriptlen + script
-
-def create_witnessprogram(version, node, utxo, pubkey, encode_p2sh, amount):
- pkscript = witness_script(version, pubkey);
- if (encode_p2sh):
- p2sh_hash = bytes_to_hex_str(ripemd160(sha256(hex_str_to_bytes(pkscript))))
- pkscript = "a914"+p2sh_hash+"87"
- inputs = []
- outputs = {}
- inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]} )
- DUMMY_P2SH = "2MySexEGVzZpRgNQ1JdjdP5bRETznm3roQ2" # P2SH of "OP_1 OP_DROP"
- outputs[DUMMY_P2SH] = amount
- tx_to_witness = node.createrawtransaction(inputs,outputs)
- #replace dummy output with our own
- tx_to_witness = tx_to_witness[0:110] + addlength(pkscript) + tx_to_witness[-8:]
- return tx_to_witness
-
-def send_to_witness(version, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""):
- tx_to_witness = create_witnessprogram(version, node, utxo, pubkey, encode_p2sh, amount)
- if (sign):
- signed = node.signrawtransaction(tx_to_witness)
- assert("errors" not in signed or len(["errors"]) == 0)
- return node.sendrawtransaction(signed["hex"])
- else:
- if (insert_redeem_script):
- tx_to_witness = tx_to_witness[0:82] + addlength(insert_redeem_script) + tx_to_witness[84:]
-
- return node.sendrawtransaction(tx_to_witness)
-
-def getutxo(txid):
- utxo = {}
- utxo["vout"] = 0
- utxo["txid"] = txid
- return utxo
-
-class SegWitTest(BitcoinTestFramework):
-
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 3)
-
- def setup_network(self):
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]))
- self.nodes.append(start_node(2, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]))
- connect_nodes(self.nodes[1], 0)
- connect_nodes(self.nodes[2], 1)
- connect_nodes(self.nodes[0], 2)
- self.is_network_split = False
- self.sync_all()
-
- def success_mine(self, node, txid, sign, redeem_script=""):
- send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
- block = node.generate(1)
- assert_equal(len(node.getblock(block[0])["tx"]), 2)
- sync_blocks(self.nodes)
-
- def skip_mine(self, node, txid, sign, redeem_script=""):
- send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
- block = node.generate(1)
- assert_equal(len(node.getblock(block[0])["tx"]), 1)
- sync_blocks(self.nodes)
-
- def fail_accept(self, node, txid, sign, redeem_script=""):
- try:
- send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
- except JSONRPCException as exp:
- assert(exp.error["code"] == -26)
- else:
- raise AssertionError("Tx should not have been accepted")
-
- def fail_mine(self, node, txid, sign, redeem_script=""):
- send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
- try:
- node.generate(1)
- except JSONRPCException as exp:
- assert(exp.error["code"] == -1)
- else:
- raise AssertionError("Created valid block when TestBlockValidity should have failed")
- sync_blocks(self.nodes)
-
- def run_test(self):
- self.nodes[0].generate(160) #block 160
-
- self.pubkey = []
- p2sh_ids = [] # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh
- wit_ids = [] # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness
- for i in range(3):
- newaddress = self.nodes[i].getnewaddress()
- self.pubkey.append(self.nodes[i].validateaddress(newaddress)["pubkey"])
- multiaddress = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]])
- self.nodes[i].addwitnessaddress(newaddress)
- self.nodes[i].addwitnessaddress(multiaddress)
- p2sh_ids.append([])
- wit_ids.append([])
- for v in range(2):
- p2sh_ids[i].append([])
- wit_ids[i].append([])
-
- for i in range(5):
- for n in range(3):
- for v in range(2):
- wit_ids[n][v].append(send_to_witness(v, self.nodes[0], self.nodes[0].listunspent()[0], self.pubkey[n], False, Decimal("49.999")))
- p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], self.nodes[0].listunspent()[0], self.pubkey[n], True, Decimal("49.999")))
-
- self.nodes[0].generate(1) #block 161
- sync_blocks(self.nodes)
-
- # Make sure all nodes recognize the transactions as theirs
- assert_equal(self.nodes[0].getbalance(), 60*50 - 60*50 + 20*Decimal("49.999") + 50)
- assert_equal(self.nodes[1].getbalance(), 20*Decimal("49.999"))
- assert_equal(self.nodes[2].getbalance(), 20*Decimal("49.999"))
-
- self.nodes[0].generate(262) #block 423
- sync_blocks(self.nodes)
-
- print("Verify default node can't accept any witness format txs before fork")
- # unsigned, no scriptsig
- self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], False)
- self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], False)
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], False)
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], False)
- # unsigned with redeem script
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], False, addlength(witness_script(0, self.pubkey[0])))
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], False, addlength(witness_script(1, self.pubkey[0])))
- # signed
- self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True)
- self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True)
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True)
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True)
-
- print("Verify witness txs are skipped for mining before the fork")
- self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) #block 424
- self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) #block 425
- self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) #block 426
- self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True) #block 427
-
- # TODO: An old node would see these txs without witnesses and be able to mine them
-
- print("Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork")
- self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][1], False) #block 428
- self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][1], False) #block 429
-
- print("Verify unsigned p2sh witness txs without a redeem script are invalid")
- self.fail_accept(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False)
- self.fail_accept(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False)
-
- print("Verify unsigned p2sh witness txs with a redeem script in versionbits-settings blocks are valid before the fork")
- self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False, addlength(witness_script(0, self.pubkey[2]))) #block 430
- self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False, addlength(witness_script(1, self.pubkey[2]))) #block 431
-
- print("Verify previous witness txs skipped for mining can now be mined")
- assert_equal(len(self.nodes[2].getrawmempool()), 4)
- block = self.nodes[2].generate(1) #block 432 (first block with new rules; 432 = 144 * 3)
- sync_blocks(self.nodes)
- assert_equal(len(self.nodes[2].getrawmempool()), 0)
- assert_equal(len(self.nodes[2].getblock(block[0])["tx"]), 5)
-
- print("Verify witness txs without witness data are invalid after the fork")
- self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False)
- self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][2], False)
- self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][2], False, addlength(witness_script(0, self.pubkey[2])))
- self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][2], False, addlength(witness_script(1, self.pubkey[2])))
-
- print("Verify default node can now use witness txs")
- self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) #block 432
- self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) #block 433
- self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) #block 434
- self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) #block 435
-
-if __name__ == '__main__':
- SegWitTest().main()
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
deleted file mode 100755
index 0dfece6b27..0000000000
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ /dev/null
@@ -1,214 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-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.
-
-# Base class for RPC testing
-
-import logging
-import optparse
-import os
-import sys
-import shutil
-import tempfile
-import traceback
-
-from .util import (
- initialize_chain,
- start_nodes,
- connect_nodes_bi,
- sync_blocks,
- sync_mempools,
- stop_nodes,
- stop_node,
- wait_bitcoinds,
- enable_coverage,
- check_json_precision,
- initialize_chain_clean,
- PortSeed,
-)
-from .authproxy import JSONRPCException
-
-
-class BitcoinTestFramework(object):
-
- def __init__(self):
- self.num_nodes = 4
- self.setup_clean_chain = False
- self.nodes = None
-
- def run_test(self):
- raise NotImplementedError
-
- def add_options(self, parser):
- pass
-
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- if self.setup_clean_chain:
- initialize_chain_clean(self.options.tmpdir, self.num_nodes)
- else:
- initialize_chain(self.options.tmpdir, self.num_nodes)
-
- def stop_node(self, num_node):
- stop_node(self.nodes[num_node], num_node)
-
- def setup_nodes(self):
- return start_nodes(self.num_nodes, self.options.tmpdir)
-
- def setup_network(self, split = False):
- self.nodes = self.setup_nodes()
-
- # Connect the nodes as a "chain". This allows us
- # to split the network between nodes 1 and 2 to get
- # two halves that can work on competing chains.
-
- # If we joined network halves, connect the nodes from the joint
- # on outward. This ensures that chains are properly reorganised.
- if not split:
- connect_nodes_bi(self.nodes, 1, 2)
- sync_blocks(self.nodes[1:3])
- sync_mempools(self.nodes[1:3])
-
- connect_nodes_bi(self.nodes, 0, 1)
- connect_nodes_bi(self.nodes, 2, 3)
- self.is_network_split = split
- self.sync_all()
-
- def split_network(self):
- """
- Split the network of four nodes into nodes 0/1 and 2/3.
- """
- assert not self.is_network_split
- stop_nodes(self.nodes)
- wait_bitcoinds()
- self.setup_network(True)
-
- def sync_all(self):
- if self.is_network_split:
- sync_blocks(self.nodes[:2])
- sync_blocks(self.nodes[2:])
- sync_mempools(self.nodes[:2])
- sync_mempools(self.nodes[2:])
- else:
- sync_blocks(self.nodes)
- sync_mempools(self.nodes)
-
- def join_network(self):
- """
- Join the (previously split) network halves together.
- """
- assert self.is_network_split
- stop_nodes(self.nodes)
- wait_bitcoinds()
- self.setup_network(False)
-
- def main(self):
-
- parser = optparse.OptionParser(usage="%prog [options]")
- parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
- help="Leave bitcoinds and test.* datadir on exit or error")
- parser.add_option("--noshutdown", dest="noshutdown", default=False, action="store_true",
- help="Don't stop bitcoinds after the test execution")
- parser.add_option("--srcdir", dest="srcdir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../../src"),
- help="Source directory containing bitcoind/bitcoin-cli (default: %default)")
- parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
- help="Root directory for datadirs")
- parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true",
- help="Print out all RPC calls as they are made")
- parser.add_option("--portseed", dest="port_seed", default=os.getpid(), type='int',
- help="The seed to use for assigning port numbers (default: current process id)")
- parser.add_option("--coveragedir", dest="coveragedir",
- help="Write tested RPC commands into this directory")
- self.add_options(parser)
- (self.options, self.args) = parser.parse_args()
-
- self.options.tmpdir += '/' + str(self.options.port_seed)
-
- if self.options.trace_rpc:
- logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
-
- if self.options.coveragedir:
- enable_coverage(self.options.coveragedir)
-
- PortSeed.n = self.options.port_seed
-
- os.environ['PATH'] = self.options.srcdir+":"+self.options.srcdir+"/qt:"+os.environ['PATH']
-
- check_json_precision()
-
- success = False
- try:
- if not os.path.isdir(self.options.tmpdir):
- os.makedirs(self.options.tmpdir)
- self.setup_chain()
-
- self.setup_network()
-
- self.run_test()
-
- success = True
-
- except JSONRPCException as e:
- print("JSONRPC error: "+e.error['message'])
- traceback.print_tb(sys.exc_info()[2])
- except AssertionError as e:
- print("Assertion failed: " + str(e))
- traceback.print_tb(sys.exc_info()[2])
- except KeyError as e:
- print("key not found: "+ str(e))
- traceback.print_tb(sys.exc_info()[2])
- except Exception as e:
- print("Unexpected exception caught during testing: " + repr(e))
- traceback.print_tb(sys.exc_info()[2])
- except KeyboardInterrupt as e:
- print("Exiting after " + repr(e))
-
- if not self.options.noshutdown:
- print("Stopping nodes")
- stop_nodes(self.nodes)
- wait_bitcoinds()
- else:
- print("Note: bitcoinds were not stopped and may still be running")
-
- if not self.options.nocleanup and not self.options.noshutdown and success:
- print("Cleaning up")
- shutil.rmtree(self.options.tmpdir)
- else:
- print("Not cleaning up dir %s" % self.options.tmpdir)
-
- if success:
- print("Tests successful")
- sys.exit(0)
- else:
- print("Failed")
- sys.exit(1)
-
-
-# Test framework for doing p2p comparison testing, which sets up some bitcoind
-# binaries:
-# 1 binary: test binary
-# 2 binaries: 1 test binary, 1 ref binary
-# n>2 binaries: 1 test binary, n-1 ref binaries
-
-class ComparisonTestFramework(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.num_nodes = 2
- self.setup_clean_chain = True
-
- def add_options(self, parser):
- parser.add_option("--testbinary", dest="testbinary",
- default=os.getenv("BITCOIND", "bitcoind"),
- help="bitcoind binary to test")
- parser.add_option("--refbinary", dest="refbinary",
- default=os.getenv("BITCOIND", "bitcoind"),
- help="bitcoind binary to use for reference nodes (if any)")
-
- def setup_network(self):
- self.nodes = start_nodes(
- self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes,
- binary=[self.options.testbinary] +
- [self.options.refbinary]*(self.num_nodes-1))
diff --git a/share/certs/PrivateKeyNotes.md b/share/certs/PrivateKeyNotes.md
index da299d168f..8d50144c21 100644
--- a/share/certs/PrivateKeyNotes.md
+++ b/share/certs/PrivateKeyNotes.md
@@ -2,7 +2,7 @@ Code-signing private key notes
==
The private keys for these certificates were generated on Gavin's main work machine,
-following the certificate authoritys' recommendations for generating certificate
+following the certificate authority's recommendations for generating certificate
signing requests.
For OSX, the private key was generated by Keychain.app on Gavin's main work machine.
diff --git a/share/genbuild.sh b/share/genbuild.sh
index 7db5455f63..32ef2a5755 100755
--- a/share/genbuild.sh
+++ b/share/genbuild.sh
@@ -1,4 +1,8 @@
#!/bin/sh
+# Copyright (c) 2012-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.
+
if [ $# -gt 1 ]; then
cd "$2"
fi
diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in
index 6a34d64cd5..5ca6d9d015 100644
--- a/share/qt/Info.plist.in
+++ b/share/qt/Info.plist.in
@@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>LSMinimumSystemVersion</key>
- <string>10.7.0</string>
+ <string>10.8.0</string>
<key>LSArchitecturePriority</key>
<array>
diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py
index 2ba8bb9b3a..5492fdb8c5 100755
--- a/share/qt/extract_strings_qt.py
+++ b/share/qt/extract_strings_qt.py
@@ -1,11 +1,13 @@
-#!/usr/bin/python
+#!/usr/bin/env python
+# Copyright (c) 2012-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.
'''
Extract _("...") strings for translation and convert to Qt stringdefs so that
they can be picked up by Qt linguist.
'''
from __future__ import division,print_function,unicode_literals
from subprocess import Popen, PIPE
-import glob
import operator
import os
import sys
diff --git a/share/qt/protobuf.pri b/share/qt/protobuf.pri
deleted file mode 100644
index 865fe86555..0000000000
--- a/share/qt/protobuf.pri
+++ /dev/null
@@ -1,35 +0,0 @@
-# Based on: http://code.google.com/p/ostinato/source/browse/protobuf.pri
-#
-# Qt qmake integration with Google Protocol Buffers compiler protoc
-#
-# To compile protocol buffers with qt qmake, specify PROTOS variable and
-# include this file
-#
-# Example:
-# PROTOS = a.proto b.proto
-# include(protobuf.pri)
-#
-# Set PROTO_PATH if you need to set the protoc --proto_path search path
-# Set PROTOC to the path to the protoc compiler if it is not in your $PATH
-#
-
-isEmpty(PROTO_DIR):PROTO_DIR = .
-isEmpty(PROTOC):PROTOC = protoc
-
-PROTOPATHS =
-for(p, PROTO_PATH):PROTOPATHS += --proto_path=$${p}
-
-protobuf_decl.name = protobuf header
-protobuf_decl.input = PROTOS
-protobuf_decl.output = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.h
-protobuf_decl.commands = $${PROTOC} --cpp_out="$${PROTO_DIR}" $${PROTOPATHS} --proto_path=${QMAKE_FILE_IN_PATH} ${QMAKE_FILE_NAME}
-protobuf_decl.variable_out = GENERATED_FILES
-QMAKE_EXTRA_COMPILERS += protobuf_decl
-
-protobuf_impl.name = protobuf implementation
-protobuf_impl.input = PROTOS
-protobuf_impl.output = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.cc
-protobuf_impl.depends = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.h
-protobuf_impl.commands = $$escape_expand(\\n)
-protobuf_impl.variable_out = GENERATED_SOURCES
-QMAKE_EXTRA_COMPILERS += protobuf_impl
diff --git a/share/rpcuser/rpcuser.py b/share/rpcuser/rpcuser.py
index 9fd176908b..63c69e308a 100755
--- a/share/rpcuser/rpcuser.py
+++ b/share/rpcuser/rpcuser.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python2
-# Copyright (c) 2015 The Bitcoin Core developers
+# Copyright (c) 2015-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.
diff --git a/src/.clang-format b/src/.clang-format
index 129f062ef8..fc53509138 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
diff --git a/src/Makefile.am b/src/Makefile.am
index e3eaacdb4c..14d55a944f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,11 @@
+# Copyright (c) 2013-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.
+
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 =
@@ -57,6 +61,7 @@ EXTRA_LIBRARIES += \
lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
bin_PROGRAMS =
+noinst_PROGRAMS =
TESTS =
BENCHMARKS =
@@ -71,6 +76,7 @@ endif
.PHONY: FORCE check-symbols check-security
# bitcoin core #
BITCOIN_CORE_H = \
+ addrdb.h \
addrman.h \
base58.h \
bloom.h \
@@ -82,7 +88,6 @@ BITCOIN_CORE_H = \
checkpoints.h \
checkqueue.h \
clientversion.h \
- coincontrol.h \
coins.h \
compat.h \
compat/byteswap.h \
@@ -92,6 +97,8 @@ BITCOIN_CORE_H = \
consensus/consensus.h \
core_io.h \
core_memusage.h \
+ cuckoocache.h \
+ fs.h \
httprpc.h \
httpserver.h \
indirectmap.h \
@@ -100,13 +107,16 @@ BITCOIN_CORE_H = \
keystore.h \
dbwrapper.h \
limitedmap.h \
- main.h \
memusage.h \
merkleblock.h \
miner.h \
net.h \
+ net_processing.h \
+ netaddress.h \
netbase.h \
+ netmessagemaker.h \
noui.h \
+ policy/feerate.h \
policy/fees.h \
policy/policy.h \
policy/rbf.h \
@@ -114,6 +124,7 @@ BITCOIN_CORE_H = \
protocol.h \
random.h \
reverselock.h \
+ rpc/blockchain.h \
rpc/client.h \
rpc/protocol.h \
rpc/server.h \
@@ -127,9 +138,11 @@ BITCOIN_CORE_H = \
support/allocators/secure.h \
support/allocators/zeroafterfree.h \
support/cleanse.h \
- support/pagelocker.h \
+ support/events.h \
+ support/lockedpool.h \
sync.h \
threadsafety.h \
+ threadinterrupt.h \
timedata.h \
torcontrol.h \
txdb.h \
@@ -139,13 +152,17 @@ BITCOIN_CORE_H = \
util.h \
utilmoneystr.h \
utiltime.h \
+ validation.h \
validationinterface.h \
versionbits.h \
+ wallet/coincontrol.h \
wallet/crypter.h \
wallet/db.h \
+ wallet/feebumper.h \
wallet/rpcwallet.h \
wallet/wallet.h \
wallet/walletdb.h \
+ warnings.h \
zmq/zmqabstractnotifier.h \
zmq/zmqconfig.h\
zmq/zmqnotificationinterface.h \
@@ -154,14 +171,15 @@ 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 = \
+ addrdb.cpp \
addrman.cpp \
bloom.cpp \
blockencodings.cpp \
@@ -171,10 +189,10 @@ libbitcoin_server_a_SOURCES = \
httpserver.cpp \
init.cpp \
dbwrapper.cpp \
- main.cpp \
merkleblock.cpp \
miner.cpp \
net.cpp \
+ net_processing.cpp \
noui.cpp \
policy/fees.cpp \
policy/policy.cpp \
@@ -193,6 +211,7 @@ libbitcoin_server_a_SOURCES = \
txdb.cpp \
txmempool.cpp \
ui_interface.cpp \
+ validation.cpp \
validationinterface.cpp \
versionbits.cpp \
$(BITCOIN_CORE_H)
@@ -214,6 +233,7 @@ libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_a_SOURCES = \
wallet/crypter.cpp \
wallet/db.cpp \
+ wallet/feebumper.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/wallet.cpp \
@@ -227,6 +247,8 @@ 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 \
@@ -280,7 +302,6 @@ 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 \
chainparams.cpp \
coins.cpp \
@@ -289,11 +310,14 @@ libbitcoin_common_a_SOURCES = \
core_write.cpp \
key.cpp \
keystore.cpp \
+ netaddress.cpp \
netbase.cpp \
+ policy/feerate.cpp \
protocol.cpp \
scheduler.cpp \
script/sign.cpp \
script/standard.cpp \
+ warnings.cpp \
$(BITCOIN_CORE_H)
# util: shared between all executables.
@@ -302,16 +326,18 @@ libbitcoin_common_a_SOURCES = \
libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_util_a_SOURCES = \
- support/pagelocker.cpp \
+ support/lockedpool.cpp \
chainparamsbase.cpp \
clientversion.cpp \
compat/glibc_sanity.cpp \
compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \
+ fs.cpp \
random.cpp \
rpc/protocol.cpp \
support/cleanse.cpp \
sync.cpp \
+ threadinterrupt.cpp \
util.cpp \
utilmoneystr.cpp \
utilstrencodings.cpp \
@@ -439,6 +465,14 @@ DISTCLEANFILES = 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 4067ceb399..3bcecab596 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -1,16 +1,34 @@
+# Copyright (c) 2015-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.
+
bin_PROGRAMS += bench/bench_bitcoin
BENCH_SRCDIR = bench
BENCH_BINARY = bench/bench_bitcoin$(EXEEXT)
+RAW_TEST_FILES = \
+ bench/data/block413567.raw
+GENERATED_TEST_FILES = $(RAW_TEST_FILES:.raw=.raw.h)
bench_bench_bitcoin_SOURCES = \
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 \
- bench/base58.cpp
+ bench/ccoins_caching.cpp \
+ bench/mempool_eviction.cpp \
+ bench/verify_script.cpp \
+ bench/base58.cpp \
+ bench/lockedpool.cpp \
+ bench/perf.cpp \
+ bench/perf.h \
+ bench/prevector_destructor.cpp
+
+nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_TEST_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)
@@ -30,16 +48,19 @@ bench_bench_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
if ENABLE_WALLET
-bench_bench_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
+bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
+bench_bench_bitcoin_LDADD += $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CRYPTO)
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
+CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_TEST_FILES)
CLEANFILES += $(CLEAN_BITCOIN_BENCH)
+bench/checkblock.cpp: bench/data/block413567.raw.h
+
bitcoin_bench: $(BENCH_BINARY)
bench: $(BENCH_BINARY) FORCE
@@ -47,3 +68,12 @@ bench: $(BENCH_BINARY) FORCE
bitcoin_bench_clean : FORCE
rm -f $(CLEAN_BITCOIN_BENCH) $(bench_bench_bitcoin_OBJECTS) $(BENCH_BINARY)
+
+%.raw.h: %.raw
+ @$(MKDIR_P) $(@D)
+ @{ \
+ echo "static unsigned const char $(*F)[] = {" && \
+ $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
+ echo "};"; \
+ } > "$@.new" && mv -f "$@.new" "$@"
+ @echo "Generated $@"
diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include
index 4b3cd6364a..358f39cbef 100644
--- a/src/Makefile.leveldb.include
+++ b/src/Makefile.leveldb.include
@@ -1,3 +1,7 @@
+# Copyright (c) 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.
+
LIBLEVELDB_INT = leveldb/libleveldb.a
LIBMEMENV_INT = leveldb/libmemenv.a
@@ -113,7 +117,6 @@ leveldb_libleveldb_a_SOURCES += leveldb/util/comparator.cc
leveldb_libleveldb_a_SOURCES += leveldb/util/crc32c.cc
leveldb_libleveldb_a_SOURCES += leveldb/util/env.cc
leveldb_libleveldb_a_SOURCES += leveldb/util/env_posix.cc
-leveldb_libleveldb_a_SOURCES += leveldb/util/env_win.cc
leveldb_libleveldb_a_SOURCES += leveldb/util/filter_policy.cc
leveldb_libleveldb_a_SOURCES += leveldb/util/hash.cc
leveldb_libleveldb_a_SOURCES += leveldb/util/histogram.cc
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 7730aba375..48411f29ec 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -1,3 +1,7 @@
+# Copyright (c) 2013-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.
+
bin_PROGRAMS += qt/bitcoin-qt
EXTRA_LIBRARIES += qt/libbitcoinqt.a
@@ -7,12 +11,11 @@ QT_TS = \
qt/locale/bitcoin_af_ZA.ts \
qt/locale/bitcoin_ar.ts \
qt/locale/bitcoin_be_BY.ts \
- qt/locale/bitcoin_bg.ts \
qt/locale/bitcoin_bg_BG.ts \
+ qt/locale/bitcoin_bg.ts \
qt/locale/bitcoin_ca_ES.ts \
qt/locale/bitcoin_ca.ts \
qt/locale/bitcoin_ca@valencia.ts \
- qt/locale/bitcoin_cs_CZ.ts \
qt/locale/bitcoin_cs.ts \
qt/locale/bitcoin_cy.ts \
qt/locale/bitcoin_da.ts \
@@ -31,6 +34,7 @@ QT_TS = \
qt/locale/bitcoin_es.ts \
qt/locale/bitcoin_es_UY.ts \
qt/locale/bitcoin_es_VE.ts \
+ qt/locale/bitcoin_et_EE.ts \
qt/locale/bitcoin_et.ts \
qt/locale/bitcoin_eu_ES.ts \
qt/locale/bitcoin_fa_IR.ts \
@@ -60,6 +64,7 @@ QT_TS = \
qt/locale/bitcoin_mn.ts \
qt/locale/bitcoin_ms_MY.ts \
qt/locale/bitcoin_nb.ts \
+ qt/locale/bitcoin_ne.ts \
qt/locale/bitcoin_nl.ts \
qt/locale/bitcoin_pam.ts \
qt/locale/bitcoin_pl.ts \
@@ -96,6 +101,7 @@ QT_FORMS_UI = \
qt/forms/editaddressdialog.ui \
qt/forms/helpmessagedialog.ui \
qt/forms/intro.ui \
+ qt/forms/modaloverlay.ui \
qt/forms/openuridialog.ui \
qt/forms/optionsdialog.ui \
qt/forms/overviewpage.ui \
@@ -116,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 \
@@ -125,6 +132,7 @@ QT_MOC_CPP = \
qt/moc_intro.cpp \
qt/moc_macdockiconhandler.cpp \
qt/moc_macnotificationhandler.cpp \
+ qt/moc_modaloverlay.cpp \
qt/moc_notificator.cpp \
qt/moc_openuridialog.cpp \
qt/moc_optionsdialog.cpp \
@@ -160,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
@@ -182,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 \
@@ -192,6 +202,7 @@ BITCOIN_QT_H = \
qt/intro.h \
qt/macdockiconhandler.h \
qt/macnotificationhandler.h \
+ qt/modaloverlay.h \
qt/networkstyle.h \
qt/notificator.h \
qt/openuridialog.h \
@@ -257,11 +268,14 @@ RES_ICONS = \
qt/res/icons/filesave.png \
qt/res/icons/fontbigger.png \
qt/res/icons/fontsmaller.png \
+ qt/res/icons/hd_disabled.png \
+ qt/res/icons/hd_enabled.png \
qt/res/icons/history.png \
qt/res/icons/info.png \
qt/res/icons/key.png \
qt/res/icons/lock_closed.png \
qt/res/icons/lock_open.png \
+ qt/res/icons/network_disabled.png \
qt/res/icons/open.png \
qt/res/icons/overview.png \
qt/res/icons/quit.png \
@@ -271,16 +285,16 @@ RES_ICONS = \
qt/res/icons/synced.png \
qt/res/icons/transaction0.png \
qt/res/icons/transaction2.png \
+ qt/res/icons/transaction_abandoned.png \
qt/res/icons/transaction_conflicted.png \
qt/res/icons/tx_inout.png \
qt/res/icons/tx_input.png \
qt/res/icons/tx_output.png \
qt/res/icons/tx_mined.png \
qt/res/icons/warning.png \
- qt/res/icons/verify.png \
- qt/res/icons/transaction_abandoned.png
+ qt/res/icons/verify.png
-BITCOIN_QT_CPP = \
+BITCOIN_QT_BASE_CPP = \
qt/bantablemodel.cpp \
qt/bitcoinaddressvalidator.cpp \
qt/bitcoinamountfield.cpp \
@@ -290,6 +304,7 @@ BITCOIN_QT_CPP = \
qt/csvmodelwriter.cpp \
qt/guiutil.cpp \
qt/intro.cpp \
+ qt/modaloverlay.cpp \
qt/networkstyle.cpp \
qt/notificator.cpp \
qt/optionsdialog.cpp \
@@ -303,12 +318,9 @@ BITCOIN_QT_CPP = \
qt/trafficgraphwidget.cpp \
qt/utilitydialog.cpp
-if TARGET_WINDOWS
-BITCOIN_QT_CPP += qt/winshutdownmonitor.cpp
-endif
+BITCOIN_QT_WINDOWS_CPP = qt/winshutdownmonitor.cpp
-if ENABLE_WALLET
-BITCOIN_QT_CPP += \
+BITCOIN_QT_WALLET_CPP = \
qt/addressbookpage.cpp \
qt/addresstablemodel.cpp \
qt/askpassphrasedialog.cpp \
@@ -335,11 +347,18 @@ BITCOIN_QT_CPP += \
qt/walletmodel.cpp \
qt/walletmodeltransaction.cpp \
qt/walletview.cpp
+
+BITCOIN_QT_CPP = $(BITCOIN_QT_BASE_CPP)
+if TARGET_WINDOWS
+BITCOIN_QT_CPP += $(BITCOIN_QT_WINDOWS_CPP)
+endif
+if ENABLE_WALLET
+BITCOIN_QT_CPP += $(BITCOIN_QT_WALLET_CPP)
endif
RES_IMAGES =
-RES_MOVIES = $(wildcard qt/res/movies/spinner-*.png)
+RES_MOVIES = $(wildcard $(srcdir)/qt/res/movies/spinner-*.png)
BITCOIN_RC = qt/res/bitcoin-qt-res.rc
@@ -399,11 +418,11 @@ QT_QM=$(QT_TS:.ts=.qm)
SECONDARY: $(QT_QM)
-$(srcdir)/qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES)
+$(srcdir)/qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_zmq_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) $(libbitcoin_util_a_SOURCES)
@test -n $(XGETTEXT) || echo "xgettext is required for updating translations"
$(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" COPYRIGHT_HOLDERS_SUBSTITUTION="$(COPYRIGHT_HOLDERS_SUBSTITUTION)" $(PYTHON) ../share/qt/extract_strings_qt.py $^
-translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM)
+translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) qt/bitcoin.cpp $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM)
@test -n $(LUPDATE) || echo "lupdate is required for updating translations"
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts $(srcdir)/qt/locale/bitcoin_en.ts
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 813a343ffa..948e13a9e1 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -1,27 +1,52 @@
+# Copyright (c) 2013-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.
+
bin_PROGRAMS += qt/test/test_bitcoin-qt
TESTS += qt/test/test_bitcoin-qt
-TEST_QT_MOC_CPP = qt/test/moc_uritests.cpp
+TEST_QT_MOC_CPP = \
+ qt/test/moc_compattests.cpp \
+ qt/test/moc_rpcnestedtests.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 = \
+ qt/test/compattests.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/testutil.cpp
+
+TEST_BITCOIN_H = \
+ test/test_bitcoin.h \
+ test/testutil.h
qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
qt_test_test_bitcoin_qt_SOURCES = \
+ qt/test/compattests.cpp \
+ 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
endif
nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 27e7694748..10cb7e775a 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -1,26 +1,13 @@
+# Copyright (c) 2013-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.
+
TESTS += test/test_bitcoin
bin_PROGRAMS += test/test_bitcoin
+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/blanktx.hex \
- test/data/tt-delin1-out.hex \
- test/data/tt-delout1-out.hex \
- test/data/tt-locktime317000-out.hex \
- test/data/tx394b54bb.hex \
- test/data/txcreate1.hex \
- test/data/txcreate2.hex \
- test/data/txcreatedata1.hex \
- test/data/txcreatedata2.hex \
- test/data/txcreatesign.hex \
- test/data/txcreatedata_seq0.hex \
- test/data/txcreatedata_seq1.hex
-
JSON_TEST_FILES = \
test/data/script_tests.json \
test/data/base58_keys_valid.json \
@@ -34,6 +21,7 @@ RAW_TEST_FILES =
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
+# test_bitcoin binary #
BITCOIN_TESTS =\
test/arith_uint256_tests.cpp \
test/scriptnum10.h \
@@ -46,10 +34,12 @@ BITCOIN_TESTS =\
test/bip32_tests.cpp \
test/blockencodings_tests.cpp \
test/bloom_tests.cpp \
- test/Checkpoints_tests.cpp \
+ test/bswap_tests.cpp \
+ test/checkqueue_tests.cpp \
test/coins_tests.cpp \
test/compress_tests.cpp \
test/crypto_tests.cpp \
+ test/cuckoocache_tests.cpp \
test/DoS_tests.cpp \
test/getarg_tests.cpp \
test/hash_tests.cpp \
@@ -67,6 +57,8 @@ BITCOIN_TESTS =\
test/policyestimator_tests.cpp \
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 \
@@ -81,6 +73,8 @@ BITCOIN_TESTS =\
test/streams_tests.cpp \
test/test_bitcoin.cpp \
test/test_bitcoin.h \
+ test/test_bitcoin_main.cpp \
+ test/test_random.h \
test/testutil.cpp \
test/testutil.h \
test/timedata_tests.cpp \
@@ -97,14 +91,13 @@ BITCOIN_TESTS += \
wallet/test/wallet_test_fixture.h \
wallet/test/accounting_tests.cpp \
wallet/test/wallet_tests.cpp \
- wallet/test/crypto_tests.cpp \
- wallet/test/rpc_wallet_tests.cpp
+ wallet/test/crypto_tests.cpp
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)
+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)
+ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
@@ -116,6 +109,25 @@ test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -s
if ENABLE_ZMQ
test_test_bitcoin_LDADD += $(ZMQ_LIBS)
endif
+#
+
+# test_bitcoin_fuzzy binary #
+test_test_bitcoin_fuzzy_SOURCES = test/test_bitcoin_fuzzy.cpp
+test_test_bitcoin_fuzzy_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_test_bitcoin_fuzzy_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_test_bitcoin_fuzzy_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+
+test_test_bitcoin_fuzzy_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBSECP256K1)
+
+test_test_bitcoin_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+#
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
@@ -125,9 +137,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
@@ -137,8 +146,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
@@ -146,16 +155,10 @@ endif
%.json.h: %.json
@$(MKDIR_P) $(@D)
- @echo "namespace json_tests{" > $@
- @echo "static unsigned const char $(*F)[] = {" >> $@
- @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@
- @echo "};};" >> $@
- @echo "Generated $@"
-
-%.raw.h: %.raw
- @$(MKDIR_P) $(@D)
- @echo "namespace alert_tests{" > $@
- @echo "static unsigned const char $(*F)[] = {" >> $@
- @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@
- @echo "};};" >> $@
+ @{ \
+ echo "namespace json_tests{" && \
+ echo "static unsigned const char $(*F)[] = {" && \
+ $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
+ echo "};};"; \
+ } > "$@.new" && mv -f "$@.new" "$@"
@echo "Generated $@"
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
new file mode 100644
index 0000000000..a3743cd0d4
--- /dev/null
+++ b/src/addrdb.cpp
@@ -0,0 +1,218 @@
+// 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.
+
+#include "addrdb.h"
+
+#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"
+
+
+CBanDB::CBanDB()
+{
+ pathBanlist = GetDataDir() / "banlist.dat";
+}
+
+bool CBanDB::Write(const banmap_t& banSet)
+{
+ // Generate random temporary filename
+ unsigned short randv = 0;
+ GetRandBytes((unsigned char*)&randv, sizeof(randv));
+ std::string tmpfn = strprintf("banlist.dat.%04x", randv);
+
+ // serialize banlist, checksum data up to that point, then append csum
+ CDataStream ssBanlist(SER_DISK, CLIENT_VERSION);
+ ssBanlist << FLATDATA(Params().MessageStart());
+ ssBanlist << banSet;
+ uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end());
+ ssBanlist << hash;
+
+ // open temp output file, and associate with CAutoFile
+ 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());
+ }
+ FileCommit(fileout.Get());
+ fileout.fclose();
+
+ // replace existing banlist.dat, if any, with new banlist.dat.XXXX
+ if (!RenameOver(pathTmp, pathBanlist))
+ return error("%s: Rename-into-place failed", __func__);
+
+ return true;
+}
+
+bool CBanDB::Read(banmap_t& banSet)
+{
+ // open input file, and associate with CAutoFile
+ FILE *file = fsbridge::fopen(pathBanlist, "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 = fs::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 {
+ // de-serialize file header (network specific magic number) and ..
+ ssBanlist >> FLATDATA(pchMsgTmp);
+
+ // ... verify the network matches ours
+ if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
+ return error("%s: Invalid network magic number", __func__);
+
+ // de-serialize ban data
+ ssBanlist >> banSet;
+ }
+ catch (const std::exception& e) {
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+
+ return true;
+}
+
+CAddrDB::CAddrDB()
+{
+ pathAddr = GetDataDir() / "peers.dat";
+}
+
+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;
+
+ // open temp output file, and associate with CAutoFile
+ 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 << ssPeers;
+ }
+ catch (const std::exception& e) {
+ return error("%s: Serialize or I/O error - %s", __func__, e.what());
+ }
+ FileCommit(fileout.Get());
+ fileout.fclose();
+
+ // replace existing peers.dat, if any, with new peers.dat.XXXX
+ if (!RenameOver(pathTmp, pathAddr))
+ return error("%s: Rename-into-place failed", __func__);
+
+ return true;
+}
+
+bool CAddrDB::Read(CAddrMan& addr)
+{
+ // open input file, and associate with CAutoFile
+ FILE *file = fsbridge::fopen(pathAddr, "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 = fs::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);
+}
+
+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
+ addr.Clear();
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+
+ return true;
+}
diff --git a/src/addrdb.h b/src/addrdb.h
new file mode 100644
index 0000000000..c3d509bd3a
--- /dev/null
+++ b/src/addrdb.h
@@ -0,0 +1,102 @@
+// 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_ADDRDB_H
+#define BITCOIN_ADDRDB_H
+
+#include "fs.h"
+#include "serialize.h"
+
+#include <string>
+#include <map>
+
+class CSubNet;
+class CAddrMan;
+class CDataStream;
+
+typedef enum BanReason
+{
+ BanReasonUnknown = 0,
+ BanReasonNodeMisbehaving = 1,
+ BanReasonManuallyAdded = 2
+} BanReason;
+
+class CBanEntry
+{
+public:
+ static const int CURRENT_VERSION=1;
+ int nVersion;
+ int64_t nCreateTime;
+ int64_t nBanUntil;
+ uint8_t banReason;
+
+ CBanEntry()
+ {
+ SetNull();
+ }
+
+ CBanEntry(int64_t nCreateTimeIn)
+ {
+ SetNull();
+ nCreateTime = nCreateTimeIn;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(this->nVersion);
+ READWRITE(nCreateTime);
+ READWRITE(nBanUntil);
+ READWRITE(banReason);
+ }
+
+ void SetNull()
+ {
+ nVersion = CBanEntry::CURRENT_VERSION;
+ nCreateTime = 0;
+ nBanUntil = 0;
+ banReason = BanReasonUnknown;
+ }
+
+ std::string banReasonToString()
+ {
+ switch (banReason) {
+ case BanReasonNodeMisbehaving:
+ return "node misbehaving";
+ case BanReasonManuallyAdded:
+ return "manually added";
+ default:
+ return "unknown";
+ }
+ }
+};
+
+typedef std::map<CSubNet, CBanEntry> banmap_t;
+
+/** Access to the (IP) address database (peers.dat) */
+class CAddrDB
+{
+private:
+ fs::path pathAddr;
+public:
+ CAddrDB();
+ bool Write(const CAddrMan& addr);
+ bool Read(CAddrMan& addr);
+ bool Read(CAddrMan& addr, CDataStream& ssPeers);
+};
+
+/** Access to the banlist database (banlist.dat) */
+class CBanDB
+{
+private:
+ fs::path pathBanlist;
+public:
+ CBanDB();
+ bool Write(const banmap_t& banSet);
+ bool Read(banmap_t& banSet);
+};
+
+#endif // BITCOIN_ADDRDB_H
diff --git a/src/addrman.cpp b/src/addrman.cpp
index cebb1c8e5e..4a408b9beb 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2012 Pieter Wuille
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -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)
@@ -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,6 +248,11 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
int nId;
CAddrInfo* pinfo = Find(addr, &nId);
+ // Do not set a penalty for a source's self-announcement
+ if (addr == source) {
+ nTimePenalty = 0;
+ }
+
if (pinfo) {
// periodically update nTime
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
@@ -353,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()) % ADDRMAN_TRIED_BUCKET_COUNT;
- nKBucketPos = (nKBucketPos + insecure_rand()) % 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);
@@ -370,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()) % ADDRMAN_NEW_BUCKET_COUNT;
- nUBucketPos = (nUBucketPos + insecure_rand()) % 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 1caf540758..70d907488f 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -1,12 +1,12 @@
// Copyright (c) 2012 Pieter Wuille
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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_ADDRMAN_H
#define BITCOIN_ADDRMAN_H
-#include "netbase.h"
+#include "netaddress.h"
#include "protocol.h"
#include "random.h"
#include "sync.h"
@@ -58,7 +58,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CAddress*)this);
READWRITE(source);
READWRITE(nLastSuccess);
@@ -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
*/
@@ -211,6 +216,9 @@ protected:
//! secret key to randomize bucket select with
uint256 nKey;
+ //! Source of random numbers for randomization in inner loops
+ FastRandomContext insecure_rand;
+
//! Find an entry.
CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL);
@@ -290,7 +298,7 @@ public:
* very little in common.
*/
template<typename Stream>
- void Serialize(Stream &s, int nType, int nVersionDummy) const
+ void Serialize(Stream &s) const
{
LOCK(cs);
@@ -340,7 +348,7 @@ public:
}
template<typename Stream>
- void Unserialize(Stream& s, int nType, int nVersionDummy)
+ void Unserialize(Stream& s)
{
LOCK(cs);
@@ -439,17 +447,12 @@ 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();
}
- unsigned int GetSerializeSize(int nType, int nVersion) const
- {
- return (CSizeComputer(nType, nVersion) << *this).size();
- }
-
void Clear()
{
std::vector<int>().swap(vRandom);
@@ -484,6 +487,7 @@ public:
//! Return the number of (unique) addresses in all tables.
size_t size() const
{
+ LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
return vRandom.size();
}
@@ -503,54 +507,48 @@ public:
//! Add a single address.
bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
{
+ LOCK(cs);
bool fRet = false;
- {
- LOCK(cs);
- Check();
- fRet |= Add_(addr, source, nTimePenalty);
- Check();
+ Check();
+ fRet |= Add_(addr, source, nTimePenalty);
+ Check();
+ if (fRet) {
+ LogPrint(BCLog::ADDRMAN, "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
}
- if (fRet)
- LogPrint("addrman", "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
return fRet;
}
//! Add multiple addresses.
bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
{
+ LOCK(cs);
int nAdd = 0;
- {
- LOCK(cs);
- Check();
- for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
- nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
- Check();
+ Check();
+ for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
+ nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
+ Check();
+ if (nAdd) {
+ LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
}
- if (nAdd)
- LogPrint("addrman", "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
return nAdd > 0;
}
//! Mark an entry as accessible.
void Good(const CService &addr, int64_t nTime = GetAdjustedTime())
{
- {
- LOCK(cs);
- Check();
- Good_(addr, nTime);
- Check();
- }
+ LOCK(cs);
+ Check();
+ Good_(addr, nTime);
+ Check();
}
//! Mark an entry as connection attempted to.
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
{
- {
- LOCK(cs);
- Check();
- Attempt_(addr, fCountFailure, nTime);
- Check();
- }
+ LOCK(cs);
+ Check();
+ Attempt_(addr, fCountFailure, nTime);
+ Check();
}
/**
@@ -584,12 +582,10 @@ public:
//! Mark an entry as currently-connected-to.
void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
{
- {
- LOCK(cs);
- Check();
- Connected_(addr, nTime);
- Check();
- }
+ LOCK(cs);
+ Check();
+ Connected_(addr, nTime);
+ Check();
}
void SetServices(const CService &addr, ServiceFlags nServices)
diff --git a/src/amount.h b/src/amount.h
index 5e52f37f23..2bd367cba2 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -1,15 +1,12 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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_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, int nType, int nVersion) {
- READWRITE(nSatoshisPerK);
- }
-};
-
#endif // BITCOIN_AMOUNT_H
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index 2e61363576..dd34a313b7 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin developers
+// 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.
@@ -173,9 +173,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 ba3d620158..0f6b3d4fba 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin developers
+// 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.
diff --git a/src/base58.cpp b/src/base58.cpp
index d1d60a6f1d..36b3523692 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Copyright (c) 2014-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.
@@ -25,12 +25,14 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
psz++;
// Skip and count leading '1's.
int zeroes = 0;
+ int length = 0;
while (*psz == '1') {
zeroes++;
psz++;
}
// Allocate enough space in big-endian base256 representation.
- std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up.
+ int size = strlen(psz) * 733 /1000 + 1; // log(58) / log(256), rounded up.
+ std::vector<unsigned char> b256(size);
// Process the characters.
while (*psz && !isspace(*psz)) {
// Decode base58 character
@@ -39,12 +41,14 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
return false;
// Apply "b256 = b256 * 58 + ch".
int carry = ch - pszBase58;
- for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) {
+ int i = 0;
+ for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {
carry += 58 * (*it);
*it = carry % 256;
carry /= 256;
}
assert(carry == 0);
+ length = i;
psz++;
}
// Skip trailing spaces.
@@ -53,7 +57,7 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
if (*psz != 0)
return false;
// Skip leading zeroes in b256.
- std::vector<unsigned char>::iterator it = b256.begin();
+ std::vector<unsigned char>::iterator it = b256.begin() + (size - length);
while (it != b256.end() && *it == 0)
it++;
// Copy result into output vector.
@@ -130,7 +134,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();
diff --git a/src/base58.h b/src/base58.h
index cccebc9e0e..3998283bb1 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -147,7 +147,7 @@ public:
K GetKey() {
K ret;
if (vchData.size() == Size) {
- //if base58 encouded data not holds a ext key, return a !IsValid() key
+ // If base58 encoded data does not hold an ext key, return a !IsValid() key
ret.Decode(&vchData[0]);
}
return ret;
diff --git a/src/bench/Examples.cpp b/src/bench/Examples.cpp
index b6b020a971..314947d48c 100644
--- a/src/bench/Examples.cpp
+++ b/src/bench/Examples.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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 "bench.h"
-#include "main.h"
+#include "validation.h"
#include "utiltime.h"
// Sanity test: this should loop ten times, and
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index 1279c3e7df..3319c179bf 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2016 the Bitcoin Core developers
+// Copyright (c) 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 "bench.h"
-#include "main.h"
+#include "validation.h"
#include "base58.h"
#include <vector>
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 227546a7a7..b0df3d2b04 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -1,16 +1,18 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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 "bench.h"
+#include "perf.h"
#include <iostream>
#include <iomanip>
#include <sys/time.h>
-using namespace benchmark;
-
-std::map<std::string, BenchFunction> 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;
@@ -18,34 +20,36 @@ static double gettimedouble(void) {
return tv.tv_usec * 0.000001 + tv.tv_sec;
}
-BenchRunner::BenchRunner(std::string name, BenchFunction func)
+benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
{
- benchmarks.insert(std::make_pair(name, func));
+ benchmarks().insert(std::make_pair(name, func));
}
void
-BenchRunner::RunAll(double elapsedTimeForOne)
+benchmark::BenchRunner::RunAll(double elapsedTimeForOne)
{
- std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << "\n";
+ perf_init();
+ std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << ","
+ << "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n";
- for (std::map<std::string,BenchFunction>::iterator it = benchmarks.begin();
- it != benchmarks.end(); ++it) {
-
- State state(it->first, elapsedTimeForOne);
- BenchFunction& func = it->second;
- func(state);
+ for (const auto &p: benchmarks()) {
+ State state(p.first, elapsedTimeForOne);
+ p.second(state);
}
+ perf_fini();
}
-bool State::KeepRunning()
+bool benchmark::State::KeepRunning()
{
if (count & countMask) {
++count;
return true;
}
double now;
+ uint64_t nowCycles;
if (count == 0) {
lastTime = beginTime = now = gettimedouble();
+ lastCycles = beginCycles = nowCycles = perf_cpucycles();
}
else {
now = gettimedouble();
@@ -53,6 +57,13 @@ bool State::KeepRunning()
double elapsedOne = elapsed * countMaskInv;
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;
+ if (elapsedOneCycles < minCycles) minCycles = elapsedOneCycles;
+ if (elapsedOneCycles > maxCycles) maxCycles = elapsedOneCycles;
+
if (elapsed*128 < maxElapsed) {
// 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.
@@ -61,23 +72,33 @@ bool State::KeepRunning()
count = 0;
minTime = std::numeric_limits<double>::max();
maxTime = std::numeric_limits<double>::min();
+ minCycles = std::numeric_limits<uint64_t>::max();
+ maxCycles = std::numeric_limits<uint64_t>::min();
return true;
}
if (elapsed*16 < maxElapsed) {
- countMask = ((countMask<<1)|1) & ((1LL<<60)-1);
- countMaskInv = 1./(countMask+1);
+ uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1);
+ if ((count & newCountMask)==0) {
+ countMask = newCountMask;
+ countMaskInv = 1./(countMask+1);
+ }
}
}
lastTime = now;
+ lastCycles = nowCycles;
++count;
if (now - beginTime < maxElapsed) return true; // Keep going
--count;
+ assert(count != 0 && "count == 0 => (now == 0 && beginTime == 0) => return above");
+
// Output results
double average = (now-beginTime)/count;
- std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << "\n";
+ int64_t averageCycles = (nowCycles-beginCycles)/count;
+ std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << ","
+ << minCycles << "," << maxCycles << "," << averageCycles << "\n";
return false;
}
diff --git a/src/bench/bench.h b/src/bench/bench.h
index f13b145aaf..f12a41126c 100644
--- a/src/bench/bench.h
+++ b/src/bench/bench.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -14,7 +14,7 @@
// 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.
@@ -41,12 +41,18 @@ namespace benchmark {
double maxElapsed;
double beginTime;
double lastTime, minTime, maxTime, countMaskInv;
- int64_t count;
- int64_t countMask;
+ uint64_t count;
+ uint64_t countMask;
+ uint64_t beginCycles;
+ uint64_t lastCycles;
+ uint64_t minCycles;
+ uint64_t maxCycles;
public:
State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
minTime = std::numeric_limits<double>::max();
maxTime = std::numeric_limits<double>::min();
+ minCycles = std::numeric_limits<uint64_t>::max();
+ maxCycles = std::numeric_limits<uint64_t>::min();
countMask = 1;
countMaskInv = 1./(countMask + 1);
}
@@ -57,7 +63,8 @@ namespace benchmark {
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 db1402216d..61a0b31aed 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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 "bench.h"
#include "key.h"
-#include "main.h"
+#include "validation.h"
#include "util.h"
int
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
new file mode 100644
index 0000000000..1e8e3d462f
--- /dev/null
+++ b/src/bench/ccoins_caching.cpp
@@ -0,0 +1,87 @@
+// Copyright (c) 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 "bench.h"
+#include "coins.h"
+#include "policy/policy.h"
+#include "wallet/crypter.h"
+
+#include <vector>
+
+// FIXME: Dedup with SetupDummyInputs in test/transaction_tests.cpp.
+//
+// Helper: create two dummy transactions, each with
+// two outputs. The first has 11 and 50 CENT outputs
+// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
+// paid to a TX_PUBKEYHASH.
+//
+static std::vector<CMutableTransaction>
+SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
+{
+ std::vector<CMutableTransaction> dummyTransactions;
+ dummyTransactions.resize(2);
+
+ // Add some keys to the keystore:
+ CKey key[4];
+ for (int i = 0; i < 4; i++) {
+ key[i].MakeNewKey(i % 2);
+ keystoreRet.AddKey(key[i]);
+ }
+
+ // Create some dummy input transactions
+ dummyTransactions[0].vout.resize(2);
+ dummyTransactions[0].vout[0].nValue = 11 * CENT;
+ 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);
+
+ 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);
+
+ return dummyTransactions;
+}
+
+// Microbenchmark for simple accesses to a CCoinsViewCache database. Note from
+// laanwj, "replicating the actual usage patterns of the client is hard though,
+// many times micro-benchmarks of the database showed completely different
+// characteristics than e.g. reindex timings. But that's not a requirement of
+// every benchmark."
+// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
+static void CCoinsCaching(benchmark::State& state)
+{
+ CBasicKeyStore keystore;
+ CCoinsView coinsDummy;
+ CCoinsViewCache coins(&coinsDummy);
+ std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
+
+ CMutableTransaction t1;
+ t1.vin.resize(3);
+ t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
+ t1.vin[0].prevout.n = 1;
+ t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
+ t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();
+ t1.vin[1].prevout.n = 0;
+ t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
+ t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();
+ t1.vin[2].prevout.n = 1;
+ t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
+ t1.vout.resize(2);
+ t1.vout[0].nValue = 90 * CENT;
+ t1.vout[0].scriptPubKey << OP_1;
+
+ // Benchmark.
+ while (state.KeepRunning()) {
+ bool success = AreInputsStandard(t1, coins);
+ assert(success);
+ CAmount value = coins.GetValueIn(t1);
+ assert(value == (50 + 21 + 22) * CENT);
+ }
+}
+
+BENCHMARK(CCoinsCaching);
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
new file mode 100644
index 0000000000..195388839e
--- /dev/null
+++ b/src/bench/checkblock.cpp
@@ -0,0 +1,56 @@
+// Copyright (c) 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 "bench.h"
+
+#include "chainparams.h"
+#include "validation.h"
+#include "streams.h"
+#include "consensus/validation.h"
+
+namespace block_bench {
+#include "bench/data/block413567.raw.h"
+}
+
+// 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
+// compact block relay.
+
+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 = '\0';
+ stream.write(&a, 1); // Prevent compaction
+
+ while (state.KeepRunning()) {
+ CBlock block;
+ stream >> block;
+ assert(stream.Rewind(sizeof(block_bench::block413567)));
+ }
+}
+
+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 = '\0';
+ stream.write(&a, 1); // Prevent compaction
+
+ 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
+ stream >> block;
+ assert(stream.Rewind(sizeof(block_bench::block413567)));
+
+ CValidationState validationState;
+ assert(CheckBlock(block, validationState, chainParams->GetConsensus()));
+ }
+}
+
+BENCHMARK(DeserializeBlockTest);
+BENCHMARK(DeserializeAndCheckBlockTest);
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
new file mode 100644
index 0000000000..88a2a570f9
--- /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(){
+ }
+ 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
new file mode 100644
index 0000000000..42891f345b
--- /dev/null
+++ b/src/bench/coin_selection.cpp
@@ -0,0 +1,60 @@
+// Copyright (c) 2012-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 "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)
+{
+ int nInput = 0;
+
+ static int nextLockTime = 0;
+ CMutableTransaction tx;
+ tx.nLockTime = nextLockTime++; // so all transactions get different hashes
+ tx.vout.resize(nInput + 1);
+ tx.vout[nInput].nValue = nValue;
+ CWalletTx* wtx = new CWalletTx(&wallet, MakeTransactionRef(std::move(tx)));
+
+ int nAge = 6 * 24;
+ COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
+ vCoins.push_back(output);
+}
+
+// Simple benchmark for wallet coin selection. Note that it maybe be necessary
+// to build up more complicated scenarios in order to get meaningful
+// measurements of performance. From laanwj, "Wallet coin selection is probably
+// the hardest, as you need a wider selection of scenarios, just testing the
+// same one over and over isn't too useful. Generating random isn't useful
+// either for measurements."
+// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
+static void CoinSelection(benchmark::State& state)
+{
+ const CWallet wallet;
+ std::vector<COutput> vCoins;
+ LOCK(wallet.cs_wallet);
+
+ while (state.KeepRunning()) {
+ // Empty wallet.
+ BOOST_FOREACH (COutput output, vCoins)
+ delete output.tx;
+ vCoins.clear();
+
+ // Add coins.
+ for (int i = 0; i < 1000; i++)
+ addCoin(1000 * COIN, wallet, vCoins);
+ addCoin(3 * COIN, wallet, vCoins);
+
+ std::set<CInputCoin> setCoinsRet;
+ CAmount nValueRet;
+ bool success = wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, setCoinsRet, nValueRet);
+ assert(success);
+ assert(nValueRet == 1003 * COIN);
+ assert(setCoinsRet.size() == 2);
+ }
+}
+
+BENCHMARK(CoinSelection);
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index 168006154f..2914a36c7b 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"
@@ -22,7 +23,7 @@ static void RIPEMD160(benchmark::State& state)
uint8_t hash[CRIPEMD160::OUTPUT_SIZE];
std::vector<uint8_t> in(BUFFER_SIZE,0);
while (state.KeepRunning())
- CRIPEMD160().Write(begin_ptr(in), in.size()).Finalize(hash);
+ CRIPEMD160().Write(in.data(), in.size()).Finalize(hash);
}
static void SHA1(benchmark::State& state)
@@ -30,7 +31,7 @@ static void SHA1(benchmark::State& state)
uint8_t hash[CSHA1::OUTPUT_SIZE];
std::vector<uint8_t> in(BUFFER_SIZE,0);
while (state.KeepRunning())
- CSHA1().Write(begin_ptr(in), in.size()).Finalize(hash);
+ CSHA1().Write(in.data(), in.size()).Finalize(hash);
}
static void SHA256(benchmark::State& state)
@@ -38,7 +39,7 @@ static void SHA256(benchmark::State& state)
uint8_t hash[CSHA256::OUTPUT_SIZE];
std::vector<uint8_t> in(BUFFER_SIZE,0);
while (state.KeepRunning())
- CSHA256().Write(begin_ptr(in), in.size()).Finalize(hash);
+ CSHA256().Write(in.data(), in.size()).Finalize(hash);
}
static void SHA256_32b(benchmark::State& state)
@@ -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(begin_ptr(in), in.size()).Finalize(&in[0]);
+ CSHA256().Write(in.data(), in.size()).Finalize(&in[0]);
}
}
}
@@ -56,7 +57,7 @@ static void SHA512(benchmark::State& state)
uint8_t hash[CSHA512::OUTPUT_SIZE];
std::vector<uint8_t> in(BUFFER_SIZE,0);
while (state.KeepRunning())
- CSHA512().Write(begin_ptr(in), in.size()).Finalize(hash);
+ CSHA512().Write(in.data(), in.size()).Finalize(hash);
}
static void SipHash_32b(benchmark::State& state)
@@ -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/data/block413567.raw b/src/bench/data/block413567.raw
new file mode 100644
index 0000000000..67d2d5d382
--- /dev/null
+++ b/src/bench/data/block413567.raw
Binary files differ
diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp
new file mode 100644
index 0000000000..43a1422795
--- /dev/null
+++ b/src/bench/lockedpool.cpp
@@ -0,0 +1,47 @@
+// Copyright (c) 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 "bench.h"
+
+#include "support/lockedpool.h"
+
+#include <iostream>
+#include <vector>
+
+#define ASIZE 2048
+#define BITER 5000
+#define MSIZE 2048
+
+static void BenchLockedPool(benchmark::State& state)
+{
+ void *synth_base = reinterpret_cast<void*>(0x08000000);
+ const size_t synth_size = 1024*1024;
+ Arena b(synth_base, synth_size, 16);
+
+ std::vector<void*> addr;
+ for (int x=0; x<ASIZE; ++x)
+ addr.push_back(0);
+ 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;
+ } else if(!addr[idx]) {
+ addr[idx] = b.alloc((s >> 16) & (MSIZE-1));
+ }
+ bool lsb = s & 1;
+ s >>= 1;
+ if (lsb)
+ s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0
+ }
+ }
+ for (void *ptr: addr)
+ b.free(ptr);
+ addr.clear();
+}
+
+BENCHMARK(BenchLockedPool);
+
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
new file mode 100644
index 0000000000..073bbde016
--- /dev/null
+++ b/src/bench/mempool_eviction.cpp
@@ -0,0 +1,114 @@
+// 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.
+
+#include "bench.h"
+#include "policy/policy.h"
+#include "txmempool.h"
+
+#include <list>
+#include <vector>
+
+static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
+{
+ int64_t nTime = 0;
+ unsigned int nHeight = 1;
+ bool spendsCoinbase = false;
+ unsigned int sigOpCost = 4;
+ LockPoints lp;
+ pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
+ MakeTransactionRef(tx), nFee, nTime, nHeight,
+ spendsCoinbase, sigOpCost, lp));
+}
+
+// Right now this is only testing eviction performance in an extremely small
+// mempool. Code needs to be written to generate a much wider variety of
+// unique transactions for a more meaningful performance measurement.
+static void MempoolEviction(benchmark::State& state)
+{
+ CMutableTransaction tx1 = CMutableTransaction();
+ tx1.vin.resize(1);
+ tx1.vin[0].scriptSig = CScript() << OP_1;
+ tx1.vout.resize(1);
+ tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
+ tx1.vout[0].nValue = 10 * COIN;
+
+ CMutableTransaction tx2 = CMutableTransaction();
+ tx2.vin.resize(1);
+ tx2.vin[0].scriptSig = CScript() << OP_2;
+ tx2.vout.resize(1);
+ tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
+ tx2.vout[0].nValue = 10 * COIN;
+
+ CMutableTransaction tx3 = CMutableTransaction();
+ tx3.vin.resize(1);
+ tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
+ tx3.vin[0].scriptSig = CScript() << OP_2;
+ tx3.vout.resize(1);
+ tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
+ tx3.vout[0].nValue = 10 * COIN;
+
+ CMutableTransaction tx4 = CMutableTransaction();
+ tx4.vin.resize(2);
+ tx4.vin[0].prevout.SetNull();
+ tx4.vin[0].scriptSig = CScript() << OP_4;
+ tx4.vin[1].prevout.SetNull();
+ tx4.vin[1].scriptSig = CScript() << OP_4;
+ tx4.vout.resize(2);
+ tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
+ tx4.vout[0].nValue = 10 * COIN;
+ tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
+ tx4.vout[1].nValue = 10 * COIN;
+
+ CMutableTransaction tx5 = CMutableTransaction();
+ tx5.vin.resize(2);
+ tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);
+ tx5.vin[0].scriptSig = CScript() << OP_4;
+ tx5.vin[1].prevout.SetNull();
+ tx5.vin[1].scriptSig = CScript() << OP_5;
+ tx5.vout.resize(2);
+ tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
+ tx5.vout[0].nValue = 10 * COIN;
+ tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
+ tx5.vout[1].nValue = 10 * COIN;
+
+ CMutableTransaction tx6 = CMutableTransaction();
+ tx6.vin.resize(2);
+ tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);
+ tx6.vin[0].scriptSig = CScript() << OP_4;
+ tx6.vin[1].prevout.SetNull();
+ tx6.vin[1].scriptSig = CScript() << OP_6;
+ tx6.vout.resize(2);
+ tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
+ tx6.vout[0].nValue = 10 * COIN;
+ tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
+ tx6.vout[1].nValue = 10 * COIN;
+
+ CMutableTransaction tx7 = CMutableTransaction();
+ tx7.vin.resize(2);
+ tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);
+ tx7.vin[0].scriptSig = CScript() << OP_5;
+ tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
+ tx7.vin[1].scriptSig = CScript() << OP_6;
+ tx7.vout.resize(2);
+ tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
+ tx7.vout[0].nValue = 10 * COIN;
+ tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
+ tx7.vout[1].nValue = 10 * COIN;
+
+ CTxMemPool pool;
+
+ while (state.KeepRunning()) {
+ AddTx(tx1, 10000LL, pool);
+ AddTx(tx2, 5000LL, pool);
+ AddTx(tx3, 20000LL, pool);
+ AddTx(tx4, 7000LL, pool);
+ AddTx(tx5, 1000LL, pool);
+ AddTx(tx6, 1100LL, pool);
+ AddTx(tx7, 9000LL, pool);
+ pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4);
+ pool.TrimToSize(GetVirtualTransactionSize(tx1));
+ }
+}
+
+BENCHMARK(MempoolEviction);
diff --git a/src/bench/perf.cpp b/src/bench/perf.cpp
new file mode 100644
index 0000000000..a549ec29ea
--- /dev/null
+++ b/src/bench/perf.cpp
@@ -0,0 +1,53 @@
+// Copyright (c) 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 "perf.h"
+
+#if defined(__i386__) || defined(__x86_64__)
+
+/* These architectures support querying the cycle counter
+ * from user space, no need for any syscall overhead.
+ */
+void perf_init(void) { }
+void perf_fini(void) { }
+
+#elif defined(__linux__)
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <linux/perf_event.h>
+
+static int fd = -1;
+static struct perf_event_attr attr;
+
+void perf_init(void)
+{
+ attr.type = PERF_TYPE_HARDWARE;
+ attr.config = PERF_COUNT_HW_CPU_CYCLES;
+ fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
+}
+
+void perf_fini(void)
+{
+ if (fd != -1) {
+ close(fd);
+ }
+}
+
+uint64_t perf_cpucycles(void)
+{
+ uint64_t result = 0;
+ if (fd == -1 || read(fd, &result, sizeof(result)) < (ssize_t)sizeof(result)) {
+ return 0;
+ }
+ return result;
+}
+
+#else /* Unhandled platform */
+
+void perf_init(void) { }
+void perf_fini(void) { }
+uint64_t perf_cpucycles(void) { return 0; }
+
+#endif
diff --git a/src/bench/perf.h b/src/bench/perf.h
new file mode 100644
index 0000000000..681bd0c8a2
--- /dev/null
+++ b/src/bench/perf.h
@@ -0,0 +1,37 @@
+// Copyright (c) 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.
+
+/** Functions for measurement of CPU cycles */
+#ifndef H_PERF
+#define H_PERF
+
+#include <stdint.h>
+
+#if defined(__i386__)
+
+static inline uint64_t perf_cpucycles(void)
+{
+ uint64_t x;
+ __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
+ return x;
+}
+
+#elif defined(__x86_64__)
+
+static inline uint64_t perf_cpucycles(void)
+{
+ uint32_t hi, lo;
+ __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+ return ((uint64_t)lo)|(((uint64_t)hi)<<32);
+}
+#else
+
+uint64_t perf_cpucycles(void);
+
+#endif
+
+void perf_init(void);
+void perf_fini(void);
+
+#endif // H_PERF
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
new file mode 100644
index 0000000000..23bbadc88d
--- /dev/null
+++ b/src/bench/verify_script.cpp
@@ -0,0 +1,102 @@
+// Copyright (c) 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 "bench.h"
+#include "key.h"
+#if defined(HAVE_CONSENSUS_LIB)
+#include "script/bitcoinconsensus.h"
+#endif
+#include "script/script.h"
+#include "script/sign.h"
+#include "streams.h"
+
+// FIXME: Dedup with BuildCreditingTransaction in test/script_tests.cpp.
+static CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)
+{
+ CMutableTransaction txCredit;
+ txCredit.nVersion = 1;
+ txCredit.nLockTime = 0;
+ txCredit.vin.resize(1);
+ txCredit.vout.resize(1);
+ txCredit.vin[0].prevout.SetNull();
+ txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0);
+ txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
+ txCredit.vout[0].scriptPubKey = scriptPubKey;
+ txCredit.vout[0].nValue = 1;
+
+ return txCredit;
+}
+
+// FIXME: Dedup with BuildSpendingTransaction in test/script_tests.cpp.
+static CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit)
+{
+ CMutableTransaction txSpend;
+ txSpend.nVersion = 1;
+ txSpend.nLockTime = 0;
+ txSpend.vin.resize(1);
+ txSpend.vout.resize(1);
+ txSpend.vin[0].prevout.hash = txCredit.GetHash();
+ txSpend.vin[0].prevout.n = 0;
+ txSpend.vin[0].scriptSig = scriptSig;
+ txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
+ txSpend.vout[0].scriptPubKey = CScript();
+ txSpend.vout[0].nValue = txCredit.vout[0].nValue;
+
+ return txSpend;
+}
+
+// Microbenchmark for verification of a basic P2WPKH script. Can be easily
+// modified to measure performance of other types of scripts.
+static void VerifyScriptBench(benchmark::State& state)
+{
+ const int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH;
+ const int witnessversion = 0;
+
+ // 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);
+ CPubKey pubkey = key.GetPubKey();
+ uint160 pubkeyHash;
+ CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(pubkeyHash.begin());
+
+ // Script.
+ CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash);
+ CScript scriptSig;
+ CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG;
+ CTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
+ CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, txCredit);
+ CScriptWitness& witness = txSpend.vin[0].scriptWitness;
+ witness.stack.emplace_back();
+ key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SIGVERSION_WITNESS_V0), witness.stack.back(), 0);
+ witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL));
+ witness.stack.push_back(ToByteVector(pubkey));
+
+ // Benchmark.
+ while (state.KeepRunning()) {
+ ScriptError err;
+ bool success = VerifyScript(
+ txSpend.vin[0].scriptSig,
+ txCredit.vout[0].scriptPubKey,
+ &txSpend.vin[0].scriptWitness,
+ flags,
+ MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue),
+ &err);
+ assert(err == SCRIPT_ERR_OK);
+ assert(success);
+
+#if defined(HAVE_CONSENSUS_LIB)
+ CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ stream << txSpend;
+ int csuccess = bitcoinconsensus_verify_script_with_amount(
+ txCredit.vout[0].scriptPubKey.data(),
+ txCredit.vout[0].scriptPubKey.size(),
+ txCredit.vout[0].nValue,
+ (const unsigned char*)stream.data(), stream.size(), 0, flags, nullptr);
+ assert(csuccess == 1);
+#endif
+ }
+}
+
+BENCHMARK(VerifyScriptBench);
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index a04101d3ed..885b787b4d 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -9,40 +9,42 @@
#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/event.h>
-#include <event2/http.h>
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>
+#include "support/events.h"
#include <univalue.h>
-using namespace std;
-
static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
+static const bool DEFAULT_NAMED=false;
+static const int CONTINUE_EXECUTION=-1;
std::string HelpMessageCli()
{
- string strUsage;
+ 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"));
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("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (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)"));
return strUsage;
@@ -67,17 +69,22 @@ public:
};
-static bool AppInitRPC(int argc, char* argv[])
+//
+// This function returns either one of EXIT_ codes when it's expected to stop the process or
+// CONTINUE_EXECUTION when it's expected to continue further.
+//
+static int AppInitRPC(int argc, char* argv[])
{
//
// Parameters
//
ParseParameters(argc, argv);
- if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) {
+ if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version")) {
std::string strUsage = strprintf(_("%s RPC client version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n";
- if (!mapArgs.count("-version")) {
+ if (!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" +
" bitcoin-cli [options] help " + _("List commands") + "\n" +
" bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
@@ -85,48 +92,77 @@ static bool AppInitRPC(int argc, char* argv[])
}
fprintf(stdout, "%s", strUsage.c_str());
- return false;
+ if (argc < 2) {
+ fprintf(stderr, "Error: too few parameters\n");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
}
- if (!boost::filesystem::is_directory(GetDataDir(false))) {
- fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
- return false;
+ if (!fs::is_directory(GetDataDir(false))) {
+ fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
+ return EXIT_FAILURE;
}
try {
- ReadConfigFile(mapArgs, mapMultiArgs);
+ ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME));
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
- return false;
+ return EXIT_FAILURE;
}
// Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
try {
SelectBaseParams(ChainNameFromCommandLine());
} catch (const std::exception& e) {
fprintf(stderr, "Error: %s\n", e.what());
- return false;
+ return EXIT_FAILURE;
}
if (GetBoolArg("-rpcssl", false))
{
fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
- return false;
+ return EXIT_FAILURE;
}
- return true;
+ return CONTINUE_EXECUTION;
}
/** Reply structure for request_done to fill in */
struct HTTPReply
{
+ HTTPReply(): status(0), error(-1) {}
+
int status;
+ int error;
std::string body;
};
+const char *http_errorstring(int code)
+{
+ switch(code) {
+#if LIBEVENT_VERSION_NUMBER >= 0x02010300
+ case EVREQ_HTTP_TIMEOUT:
+ return "timeout reached";
+ case EVREQ_HTTP_EOF:
+ return "EOF reached";
+ case EVREQ_HTTP_INVALID_HEADER:
+ return "error while reading header, or invalid header";
+ case EVREQ_HTTP_BUFFER_ERROR:
+ return "error encountered while reading or writing";
+ case EVREQ_HTTP_REQUEST_CANCEL:
+ return "request was canceled";
+ case EVREQ_HTTP_DATA_TOO_LONG:
+ return "response body is larger than allowed";
+#endif
+ default:
+ return "unknown";
+ }
+}
+
static void http_request_done(struct evhttp_request *req, void *ctx)
{
HTTPReply *reply = static_cast<HTTPReply*>(ctx);
if (req == NULL) {
- /* If req is NULL, it means an error occurred while connecting, but
- * I'm not sure how to find out which one. We also don't really care.
+ /* If req is NULL, it means an error occurred while connecting: the
+ * error code will have been passed to http_error_cb.
*/
reply->status = 0;
return;
@@ -145,87 +181,91 @@ static void http_request_done(struct evhttp_request *req, void *ctx)
}
}
-UniValue CallRPC(const string& strMethod, const UniValue& params)
+#if LIBEVENT_VERSION_NUMBER >= 0x02010300
+static void http_error_cb(enum evhttp_request_error err, void *ctx)
+{
+ HTTPReply *reply = static_cast<HTTPReply*>(ctx);
+ reply->error = err;
+}
+#endif
+
+UniValue CallRPC(const std::string& strMethod, const UniValue& params)
{
std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
int port = GetArg("-rpcport", BaseParams().RPCPort());
- // Create event base
- struct event_base *base = event_base_new(); // TODO RAII
- if (!base)
- throw runtime_error("cannot create event_base");
+ // Obtain event base
+ raii_event_base base = obtain_event_base();
// Synchronously look up hostname
- struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII
- if (evcon == NULL)
- throw runtime_error("create connection failed");
- evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
+ raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
+ evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
HTTPReply response;
- struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII
+ raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
if (req == NULL)
- throw runtime_error("create http request failed");
+ throw std::runtime_error("create http request failed");
+#if LIBEVENT_VERSION_NUMBER >= 0x02010300
+ evhttp_request_set_error_cb(req.get(), http_error_cb);
+#endif
// Get credentials
std::string strRPCUserColonPass;
- if (mapArgs["-rpcpassword"] == "") {
+ if (GetArg("-rpcpassword", "") == "") {
// Try fall back to cookie-based authentication if no password is provided
if (!GetAuthCookie(&strRPCUserColonPass)) {
- throw runtime_error(strprintf(
+ 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().string().c_str()));
+ GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
}
} else {
- strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
+ strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");
}
- struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req);
+ struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
assert(output_headers);
evhttp_add_header(output_headers, "Host", host.c_str());
evhttp_add_header(output_headers, "Connection", "close");
evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
// Attach request data
- std::string strRequest = JSONRPCRequest(strMethod, params, 1);
- struct evbuffer * output_buffer = evhttp_request_get_output_buffer(req);
+ std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).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, req, EVHTTP_REQ_POST, "/");
+ int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
+ req.release(); // ownership moved to evcon in above call
if (r != 0) {
- evhttp_connection_free(evcon);
- event_base_free(base);
throw CConnectionFailed("send http request failed");
}
- event_base_dispatch(base);
- evhttp_connection_free(evcon);
- event_base_free(base);
+ event_base_dispatch(base.get());
if (response.status == 0)
- throw CConnectionFailed("couldn't connect to server");
+ throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error));
else if (response.status == HTTP_UNAUTHORIZED)
- throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
+ throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
- throw runtime_error(strprintf("server returned HTTP error %d", response.status));
+ throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
else if (response.body.empty())
- throw runtime_error("no response from server");
+ throw std::runtime_error("no response from server");
// Parse reply
UniValue valReply(UniValue::VSTR);
if (!valReply.read(response.body))
- throw runtime_error("couldn't parse reply from server");
+ throw std::runtime_error("couldn't parse reply from server");
const UniValue& reply = valReply.get_obj();
if (reply.empty())
- throw runtime_error("expected reply to have result, error and id properties");
+ throw std::runtime_error("expected reply to have result, error and id properties");
return reply;
}
int CommandLineRPC(int argc, char *argv[])
{
- string strPrint;
+ std::string strPrint;
int nRet = 0;
try {
// Skip switches
@@ -241,9 +281,16 @@ int CommandLineRPC(int argc, char *argv[])
args.push_back(line);
}
if (args.size() < 1)
- throw runtime_error("too few parameters (need at least command)");
+ throw std::runtime_error("too few parameters (need at least command)");
std::string strMethod = args[0];
- UniValue params = RPCConvertValues(strMethod, std::vector<std::string>(args.begin()+1, args.end()));
+ args.erase(args.begin()); // Remove trailing method name from arguments vector
+
+ UniValue params;
+ if(GetBoolArg("-named", DEFAULT_NAMED)) {
+ params = RPCConvertNamedValues(strMethod, args);
+ } else {
+ params = RPCConvertValues(strMethod, args);
+ }
// Execute and handle connection failures with -rpcwait
const bool fWait = GetBoolArg("-rpcwait", false);
@@ -295,7 +342,7 @@ int CommandLineRPC(int argc, char *argv[])
throw;
}
catch (const std::exception& e) {
- strPrint = string("error: ") + e.what();
+ strPrint = std::string("error: ") + e.what();
nRet = EXIT_FAILURE;
}
catch (...) {
@@ -318,8 +365,9 @@ int main(int argc, char* argv[])
}
try {
- if(!AppInitRPC(argc, argv))
- return EXIT_FAILURE;
+ int ret = AppInitRPC(argc, argv);
+ if (ret != CONTINUE_EXECUTION)
+ return ret;
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInitRPC()");
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 8e8ac47455..45738b5df8 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -26,12 +26,15 @@
#include <boost/algorithm/string.hpp>
#include <boost/assign/list_of.hpp>
-using namespace std;
-
static bool fCreateBlank;
-static map<string,UniValue> registers;
-
-static bool AppInitRawTx(int argc, char* argv[])
+static std::map<std::string,UniValue> registers;
+static const int CONTINUE_EXECUTION=-1;
+
+//
+// This function returns either one of EXIT_ codes when it's expected to stop the process or
+// CONTINUE_EXECUTION when it's expected to continue further.
+//
+static int AppInitRawTx(int argc, char* argv[])
{
//
// Parameters
@@ -43,12 +46,12 @@ static bool AppInitRawTx(int argc, char* argv[])
SelectParams(ChainNameFromCommandLine());
} catch (const std::exception& e) {
fprintf(stderr, "Error: %s\n", e.what());
- return false;
+ return EXIT_FAILURE;
}
fCreateBlank = GetBoolArg("-create", false);
- if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help"))
+ if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || 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" +
@@ -75,8 +78,16 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N"));
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
+ strUsage += HelpMessageOpt("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") + ". " +
+ _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."));
strUsage += HelpMessageOpt("outdata=[VALUE:]DATA", _("Add data-based output to TX"));
- strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX"));
+ strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT[:FLAGS]", _("Add raw script output to TX") + ". " +
+ _("Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output") + ". " +
+ _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."));
+ strUsage += HelpMessageOpt("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", _("Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS") + ". " +
+ _("Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output") + ". " +
+ _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."));
strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
_("This command requires JSON registers:") +
_("prevtxs=JSON object") + ", " +
@@ -89,57 +100,61 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage += HelpMessageOpt("set=NAME:JSON-STRING", _("Set register NAME to given JSON-STRING"));
fprintf(stdout, "%s", strUsage.c_str());
- return false;
+ if (argc < 2) {
+ fprintf(stderr, "Error: too few parameters\n");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
}
- return true;
+ return CONTINUE_EXECUTION;
}
-static void RegisterSetJson(const string& key, const string& rawJson)
+static void RegisterSetJson(const std::string& key, const std::string& rawJson)
{
UniValue val;
if (!val.read(rawJson)) {
- string strErr = "Cannot parse JSON for key " + key;
- throw runtime_error(strErr);
+ std::string strErr = "Cannot parse JSON for key " + key;
+ throw std::runtime_error(strErr);
}
registers[key] = val;
}
-static void RegisterSet(const string& strInput)
+static void RegisterSet(const std::string& strInput)
{
// separate NAME:VALUE in string
size_t pos = strInput.find(':');
- if ((pos == string::npos) ||
+ if ((pos == std::string::npos) ||
(pos == 0) ||
(pos == (strInput.size() - 1)))
- throw runtime_error("Register input requires NAME:VALUE");
+ throw std::runtime_error("Register input requires NAME:VALUE");
- string key = strInput.substr(0, pos);
- string valStr = strInput.substr(pos + 1, string::npos);
+ std::string key = strInput.substr(0, pos);
+ std::string valStr = strInput.substr(pos + 1, std::string::npos);
RegisterSetJson(key, valStr);
}
-static void RegisterLoad(const string& strInput)
+static void RegisterLoad(const std::string& strInput)
{
// separate NAME:FILENAME in string
size_t pos = strInput.find(':');
- if ((pos == string::npos) ||
+ if ((pos == std::string::npos) ||
(pos == 0) ||
(pos == (strInput.size() - 1)))
- throw runtime_error("Register load requires NAME:FILENAME");
+ throw std::runtime_error("Register load requires NAME:FILENAME");
- string key = strInput.substr(0, pos);
- string filename = strInput.substr(pos + 1, string::npos);
+ std::string key = strInput.substr(0, pos);
+ std::string filename = strInput.substr(pos + 1, std::string::npos);
FILE *f = fopen(filename.c_str(), "r");
if (!f) {
- string strErr = "Cannot open file " + filename;
- throw runtime_error(strErr);
+ std::string strErr = "Cannot open file " + filename;
+ throw std::runtime_error(strErr);
}
// load file chunks into one big buffer
- string valStr;
+ std::string valStr;
while ((!feof(f)) && (!ferror(f))) {
char buf[4096];
int bread = fread(buf, 1, sizeof(buf), f);
@@ -153,55 +168,63 @@ static void RegisterLoad(const string& strInput)
fclose(f);
if (error) {
- string strErr = "Error reading file " + filename;
- throw runtime_error(strErr);
+ std::string strErr = "Error reading file " + filename;
+ throw std::runtime_error(strErr);
}
// evaluate as JSON buffer register
RegisterSetJson(key, valStr);
}
-static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
+static CAmount ExtractAndValidateValue(const std::string& strValue)
+{
+ CAmount value;
+ if (!ParseMoney(strValue, value))
+ throw std::runtime_error("invalid TX output value");
+ return value;
+}
+
+static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
{
int64_t newVersion = atoi64(cmdVal);
- if (newVersion < 1 || newVersion > CTransaction::CURRENT_VERSION)
- throw runtime_error("Invalid TX version requested");
+ if (newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
+ throw std::runtime_error("Invalid TX version requested");
tx.nVersion = (int) newVersion;
}
-static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal)
+static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
{
int64_t newLocktime = atoi64(cmdVal);
if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
- throw runtime_error("Invalid TX locktime requested");
+ throw std::runtime_error("Invalid TX locktime requested");
tx.nLockTime = (unsigned int) newLocktime;
}
-static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
+static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
{
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
// separate TXID:VOUT in string
if (vStrInputParts.size()<2)
- throw runtime_error("TX input missing separator");
+ throw std::runtime_error("TX input missing separator");
// extract and validate TXID
- string strTxid = vStrInputParts[0];
+ std::string strTxid = vStrInputParts[0];
if ((strTxid.size() != 64) || !IsHex(strTxid))
- throw runtime_error("invalid TX input txid");
+ throw std::runtime_error("invalid TX input txid");
uint256 txid(uint256S(strTxid));
static const unsigned int minTxOutSz = 9;
static const unsigned int maxVout = MAX_BLOCK_BASE_SIZE / minTxOutSz;
// extract and validate vout
- string strVout = vStrInputParts[1];
+ std::string strVout = vStrInputParts[1];
int vout = atoi(strVout);
if ((vout < 0) || (vout > (int)maxVout))
- throw runtime_error("invalid TX input vout");
+ throw std::runtime_error("invalid TX input vout");
// extract the optional sequence number
uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max();
@@ -213,27 +236,23 @@ static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
tx.vin.push_back(txin);
}
-static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput)
+static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput)
{
- // separate VALUE:ADDRESS in string
- size_t pos = strInput.find(':');
- if ((pos == string::npos) ||
- (pos == 0) ||
- (pos == (strInput.size() - 1)))
- throw runtime_error("TX output missing separator");
+ // Separate into VALUE:ADDRESS
+ std::vector<std::string> vStrInputParts;
+ boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
- // extract and validate VALUE
- string strValue = strInput.substr(0, pos);
- CAmount value;
- if (!ParseMoney(strValue, value))
- throw runtime_error("invalid TX output value");
+ 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
- string strAddr = strInput.substr(pos + 1, string::npos);
+ std::string strAddr = vStrInputParts[1];
CBitcoinAddress addr(strAddr);
if (!addr.IsValid())
- throw runtime_error("invalid TX output address");
-
+ throw std::runtime_error("invalid TX output address");
// build standard output script via GetScriptForDestination()
CScript scriptPubKey = GetScriptForDestination(addr.Get());
@@ -242,7 +261,118 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput)
tx.vout.push_back(txout);
}
-static void MutateTxAddOutData(CMutableTransaction& tx, const string& strInput)
+static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput)
+{
+ // Separate into VALUE:PUBKEY[:FLAGS]
+ 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]);
+
+ // Extract and validate PUBKEY
+ CPubKey pubkey(ParseHex(vStrInputParts[1]));
+ 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;
+ bool bScriptHash = false;
+ if (vStrInputParts.size() == 3) {
+ std::string flags = vStrInputParts[2];
+ bSegWit = (flags.find("W") != std::string::npos);
+ bScriptHash = (flags.find("S") != std::string::npos);
+ }
+
+ if (bSegWit) {
+ // 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());
+ }
+
+ // construct TxOut, append to transaction output list
+ CTxOut txout(value, scriptPubKey);
+ tx.vout.push_back(txout);
+}
+
+static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput)
+{
+ // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
+ std::vector<std::string> vStrInputParts;
+ boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
+
+ // Check that there are enough parameters
+ if (vStrInputParts.size()<3)
+ throw std::runtime_error("Not enough multisig parameters");
+
+ // Extract and validate VALUE
+ CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
+
+ // Extract REQUIRED
+ uint32_t required = stoul(vStrInputParts[1]);
+
+ // Extract NUMKEYS
+ uint32_t numkeys = stoul(vStrInputParts[2]);
+
+ // Validate there are the correct number of pubkeys
+ if (vStrInputParts.size() < numkeys + 3)
+ throw std::runtime_error("incorrect number of multisig pubkeys");
+
+ if (required < 1 || required > 20 || numkeys < 1 || numkeys > 20 || numkeys < required)
+ throw std::runtime_error("multisig parameter mismatch. Required " \
+ + std::to_string(required) + " of " + std::to_string(numkeys) + "signatures.");
+
+ // extract and validate PUBKEYs
+ std::vector<CPubKey> pubkeys;
+ for(int pos = 1; pos <= int(numkeys); pos++) {
+ CPubKey pubkey(ParseHex(vStrInputParts[pos + 2]));
+ if (!pubkey.IsFullyValid())
+ throw std::runtime_error("invalid TX output pubkey");
+ pubkeys.push_back(pubkey);
+ }
+
+ // Extract FLAGS
+ bool bSegWit = false;
+ bool bScriptHash = false;
+ if (vStrInputParts.size() == numkeys + 4) {
+ std::string flags = vStrInputParts.back();
+ bSegWit = (flags.find("W") != std::string::npos);
+ bScriptHash = (flags.find("S") != std::string::npos);
+ }
+ else if (vStrInputParts.size() > numkeys + 4) {
+ // Validate that there were no more parameters passed
+ throw std::runtime_error("Too many parameters");
+ }
+
+ CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);
+
+ if (bSegWit) {
+ // 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());
+ }
+
+ // construct TxOut, append to transaction output list
+ CTxOut txout(value, scriptPubKey);
+ tx.vout.push_back(txout);
+}
+
+static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput)
{
CAmount value = 0;
@@ -250,20 +380,18 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const string& strInput)
size_t pos = strInput.find(':');
if (pos==0)
- throw runtime_error("TX output value not specified");
+ throw std::runtime_error("TX output value not specified");
- if (pos != string::npos) {
- // extract and validate VALUE
- string strValue = strInput.substr(0, pos);
- if (!ParseMoney(strValue, value))
- throw runtime_error("invalid TX output value");
+ if (pos != std::string::npos) {
+ // Extract and validate VALUE
+ value = ExtractAndValidateValue(strInput.substr(0, pos));
}
// extract and validate DATA
- string strData = strInput.substr(pos + 1, string::npos);
+ std::string strData = strInput.substr(pos + 1, std::string::npos);
if (!IsHex(strData))
- throw runtime_error("invalid TX output data");
+ throw std::runtime_error("invalid TX output data");
std::vector<unsigned char> data = ParseHex(strData);
@@ -271,49 +399,63 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const string& strInput)
tx.vout.push_back(txout);
}
-static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput)
+static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput)
{
- // separate VALUE:SCRIPT in string
- size_t pos = strInput.find(':');
- if ((pos == string::npos) ||
- (pos == 0))
- throw runtime_error("TX output missing separator");
+ // separate VALUE:SCRIPT[:FLAGS]
+ std::vector<std::string> vStrInputParts;
+ boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
+ if (vStrInputParts.size() < 2)
+ throw std::runtime_error("TX output missing separator");
- // extract and validate VALUE
- string strValue = strInput.substr(0, pos);
- CAmount value;
- if (!ParseMoney(strValue, value))
- throw runtime_error("invalid TX output value");
+ // Extract and validate VALUE
+ CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
// extract and validate script
- string strScript = strInput.substr(pos + 1, string::npos);
- CScript scriptPubKey = ParseScript(strScript); // throws on err
+ std::string strScript = vStrInputParts[1];
+ CScript scriptPubKey = ParseScript(strScript);
+
+ // Extract FLAGS
+ bool bSegWit = false;
+ bool bScriptHash = false;
+ if (vStrInputParts.size() == 3) {
+ std::string flags = vStrInputParts.back();
+ bSegWit = (flags.find("W") != std::string::npos);
+ bScriptHash = (flags.find("S") != std::string::npos);
+ }
+
+ if (bSegWit) {
+ scriptPubKey = GetScriptForWitness(scriptPubKey);
+ }
+ if (bScriptHash) {
+ CBitcoinAddress addr(scriptPubKey);
+ scriptPubKey = GetScriptForDestination(addr.Get());
+ }
// construct TxOut, append to transaction output list
CTxOut txout(value, scriptPubKey);
tx.vout.push_back(txout);
}
-static void MutateTxDelInput(CMutableTransaction& tx, const string& strInIdx)
+static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)
{
// parse requested deletion index
int inIdx = atoi(strInIdx);
if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
- string strErr = "Invalid TX input index '" + strInIdx + "'";
- throw runtime_error(strErr.c_str());
+ std::string strErr = "Invalid TX input index '" + strInIdx + "'";
+ throw std::runtime_error(strErr.c_str());
}
// delete input from transaction
tx.vin.erase(tx.vin.begin() + inIdx);
}
-static void MutateTxDelOutput(CMutableTransaction& tx, const string& strOutIdx)
+static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
{
// parse requested deletion index
int outIdx = atoi(strOutIdx);
if (outIdx < 0 || outIdx >= (int)tx.vout.size()) {
- string strErr = "Invalid TX output index '" + strOutIdx + "'";
- throw runtime_error(strErr.c_str());
+ std::string strErr = "Invalid TX output index '" + strOutIdx + "'";
+ throw std::runtime_error(strErr.c_str());
}
// delete output from transaction
@@ -333,7 +475,7 @@ static const struct {
{"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
};
-static bool findSighashFlags(int& flags, const string& flagStr)
+static bool findSighashFlags(int& flags, const std::string& flagStr)
{
flags = 0;
@@ -347,43 +489,27 @@ static bool findSighashFlags(int& flags, const string& flagStr)
return false;
}
-uint256 ParseHashUO(map<string,UniValue>& o, string strKey)
-{
- if (!o.count(strKey))
- return uint256();
- return ParseHashUV(o[strKey], strKey);
-}
-
-vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
-{
- if (!o.count(strKey)) {
- vector<unsigned char> emptyVec;
- return emptyVec;
- }
- return ParseHexUV(o[strKey], strKey);
-}
-
static CAmount AmountFromValue(const UniValue& value)
{
if (!value.isNum() && !value.isStr())
- throw runtime_error("Amount is not a number or string");
+ throw std::runtime_error("Amount is not a number or string");
CAmount amount;
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
- throw runtime_error("Invalid amount");
+ throw std::runtime_error("Invalid amount");
if (!MoneyRange(amount))
- throw runtime_error("Amount out of range");
+ throw std::runtime_error("Amount out of range");
return amount;
}
-static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
+static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
{
int nHashType = SIGHASH_ALL;
if (flagStr.size() > 0)
if (!findSighashFlags(nHashType, flagStr))
- throw runtime_error("unknown sighash flag/sign option");
+ throw std::runtime_error("unknown sighash flag/sign option");
- vector<CTransaction> txVariants;
+ std::vector<CTransaction> txVariants;
txVariants.push_back(tx);
// mergedTx will end up with all the signatures; it
@@ -394,19 +520,17 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
CCoinsViewCache view(&viewDummy);
if (!registers.count("privatekeys"))
- throw runtime_error("privatekeys register variable must be set.");
- bool fGivenKeys = false;
+ throw std::runtime_error("privatekeys register variable must be set.");
CBasicKeyStore tempKeystore;
UniValue keysObj = registers["privatekeys"];
- fGivenKeys = true;
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr())
- throw runtime_error("privatekey not a string");
+ throw std::runtime_error("privatekey not a std::string");
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
if (!fGood)
- throw runtime_error("privatekey not valid");
+ throw std::runtime_error("privatekey not valid");
CKey key = vchSecret.GetKey();
tempKeystore.AddKey(key);
@@ -414,34 +538,34 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
// Add previous txouts given in the RPC call:
if (!registers.count("prevtxs"))
- throw runtime_error("prevtxs register variable must be set.");
+ throw std::runtime_error("prevtxs register variable must be set.");
UniValue prevtxsObj = registers["prevtxs"];
{
for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) {
UniValue prevOut = prevtxsObj[previdx];
if (!prevOut.isObject())
- throw runtime_error("expected prevtxs internal object");
+ throw std::runtime_error("expected prevtxs internal object");
- map<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 = boost::assign::map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR);
if (!prevOut.checkObject(types))
- throw runtime_error("prevtxs internal object typecheck fail");
+ throw std::runtime_error("prevtxs internal object typecheck fail");
uint256 txid = ParseHashUV(prevOut["txid"], "txid");
int nOut = atoi(prevOut["vout"].getValStr());
if (nOut < 0)
- throw runtime_error("vout must be positive");
+ throw std::runtime_error("vout must be positive");
- vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
+ 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) {
- string err("Previous output scriptPubKey mismatch:\n");
+ std::string err("Previous output scriptPubKey mismatch:\n");
err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey);
- throw runtime_error(err);
+ throw std::runtime_error(err);
}
if ((unsigned int)nOut >= coins->vout.size())
coins->vout.resize(nOut+1);
@@ -454,10 +578,10 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
// if redeemScript given and private keys given,
// add redeemScript to the tempKeystore so it can be signed:
- if (fGivenKeys && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
+ if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
prevOut.exists("redeemScript")) {
UniValue v = prevOut["redeemScript"];
- vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
+ std::vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript);
}
@@ -489,7 +613,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i));
UpdateTransaction(mergedTx, i, sigdata);
- if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx.wit.vtxinwit.size() > i ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount)))
+ if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount)))
fComplete = false;
}
@@ -514,10 +638,10 @@ public:
}
};
-static void MutateTx(CMutableTransaction& tx, const string& command,
- const string& commandVal)
+static void MutateTx(CMutableTransaction& tx, const std::string& command,
+ const std::string& commandVal)
{
- boost::scoped_ptr<Secp256k1Init> ecc;
+ std::unique_ptr<Secp256k1Init> ecc;
if (command == "nversion")
MutateTxVersion(tx, commandVal);
@@ -533,10 +657,16 @@ static void MutateTx(CMutableTransaction& tx, const string& command,
MutateTxDelOutput(tx, commandVal);
else if (command == "outaddr")
MutateTxAddOutAddr(tx, commandVal);
+ else if (command == "outpubkey") {
+ if (!ecc) { ecc.reset(new Secp256k1Init()); }
+ MutateTxAddOutPubKey(tx, commandVal);
+ } else if (command == "outmultisig") {
+ if (!ecc) { ecc.reset(new Secp256k1Init()); }
+ MutateTxAddOutMultiSig(tx, commandVal);
+ } else if (command == "outscript")
+ MutateTxAddOutScript(tx, commandVal);
else if (command == "outdata")
MutateTxAddOutData(tx, commandVal);
- else if (command == "outscript")
- MutateTxAddOutScript(tx, commandVal);
else if (command == "sign") {
if (!ecc) { ecc.reset(new Secp256k1Init()); }
@@ -550,7 +680,7 @@ static void MutateTx(CMutableTransaction& tx, const string& command,
RegisterSet(commandVal);
else
- throw runtime_error("unknown command");
+ throw std::runtime_error("unknown command");
}
static void OutputTxJSON(const CTransaction& tx)
@@ -558,20 +688,20 @@ static void OutputTxJSON(const CTransaction& tx)
UniValue entry(UniValue::VOBJ);
TxToUniv(tx, uint256(), entry);
- string jsonOutput = entry.write(4);
+ std::string jsonOutput = entry.write(4);
fprintf(stdout, "%s\n", jsonOutput.c_str());
}
static void OutputTxHash(const CTransaction& tx)
{
- string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
+ std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
fprintf(stdout, "%s\n", strHexHash.c_str());
}
static void OutputTxHex(const CTransaction& tx)
{
- string strHex = EncodeHexTx(tx);
+ std::string strHex = EncodeHexTx(tx);
fprintf(stdout, "%s\n", strHex.c_str());
}
@@ -586,10 +716,10 @@ static void OutputTx(const CTransaction& tx)
OutputTxHex(tx);
}
-static string readStdin()
+static std::string readStdin()
{
char buf[4096];
- string ret;
+ std::string ret;
while (!feof(stdin)) {
size_t bread = fread(buf, 1, sizeof(buf), stdin);
@@ -599,7 +729,7 @@ static string readStdin()
}
if (ferror(stdin))
- throw runtime_error("error reading stdin");
+ throw std::runtime_error("error reading stdin");
boost::algorithm::trim_right(ret);
@@ -608,7 +738,7 @@ static string readStdin()
static int CommandLineRawTx(int argc, char* argv[])
{
- string strPrint;
+ std::string strPrint;
int nRet = 0;
try {
// Skip switches; Permit common stdin convention "-"
@@ -618,33 +748,31 @@ static int CommandLineRawTx(int argc, char* argv[])
argv++;
}
- CTransaction txDecodeTmp;
+ CMutableTransaction tx;
int startArg;
if (!fCreateBlank) {
// require at least one param
if (argc < 2)
- throw runtime_error("too few parameters");
+ throw std::runtime_error("too few parameters");
// param: hex-encoded bitcoin transaction
- string strHexTx(argv[1]);
+ std::string strHexTx(argv[1]);
if (strHexTx == "-") // "-" implies standard input
strHexTx = readStdin();
- if (!DecodeHexTx(txDecodeTmp, strHexTx))
- throw runtime_error("invalid transaction encoding");
+ if (!DecodeHexTx(tx, strHexTx, true))
+ throw std::runtime_error("invalid transaction encoding");
startArg = 2;
} else
startArg = 1;
- CMutableTransaction tx(txDecodeTmp);
-
for (int i = startArg; i < argc; i++) {
- string arg = argv[i];
- string key, value;
+ std::string arg = argv[i];
+ std::string key, value;
size_t eqpos = arg.find('=');
- if (eqpos == string::npos)
+ if (eqpos == std::string::npos)
key = arg;
else {
key = arg.substr(0, eqpos);
@@ -661,7 +789,7 @@ static int CommandLineRawTx(int argc, char* argv[])
throw;
}
catch (const std::exception& e) {
- strPrint = string("error: ") + e.what();
+ strPrint = std::string("error: ") + e.what();
nRet = EXIT_FAILURE;
}
catch (...) {
@@ -680,8 +808,9 @@ int main(int argc, char* argv[])
SetupEnvironment();
try {
- if(!AppInitRawTx(argc, argv))
- return EXIT_FAILURE;
+ int ret = AppInitRawTx(argc, argv);
+ if (ret != CONTINUE_EXECUTION)
+ return ret;
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInitRawTx()");
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 28bc374acc..31680a8ec7 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -9,6 +9,8 @@
#include "chainparams.h"
#include "clientversion.h"
+#include "compat.h"
+#include "fs.h"
#include "rpc/server.h"
#include "init.h"
#include "noui.h"
@@ -19,7 +21,6 @@
#include "utilstrencodings.h"
#include <boost/algorithm/string/predicate.hpp>
-#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
#include <stdio.h>
@@ -40,8 +41,6 @@
* Use the buttons <code>Namespaces</code>, <code>Classes</code> or <code>Files</code> at the top of the page to start navigating the code.
*/
-static bool fDaemon;
-
void WaitForShutdown(boost::thread_group* threadGroup)
{
bool fShutdown = ShutdownRequested();
@@ -76,11 +75,11 @@ bool AppInit(int argc, char* argv[])
ParseParameters(argc, argv);
// Process help and version before taking care about datadir
- if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version"))
+ if (IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version"))
{
std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n";
- if (mapArgs.count("-version"))
+ if (IsArgSet("-version"))
{
strUsage += FormatParagraph(LicenseInfo());
}
@@ -93,19 +92,19 @@ bool AppInit(int argc, char* argv[])
}
fprintf(stdout, "%s", strUsage.c_str());
- return false;
+ return true;
}
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", mapArgs["-datadir"].c_str());
+ fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
return false;
}
try
{
- ReadConfigFile(mapArgs, mapMultiArgs);
+ ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME));
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;
@@ -127,38 +126,45 @@ bool AppInit(int argc, char* argv[])
if (fCommandLine)
{
fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n");
- exit(1);
+ exit(EXIT_FAILURE);
+ }
+ // -server defaults to true for bitcoind but not for the GUI so do this here
+ 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(EXIT_FAILURE);
}
-#ifndef WIN32
- fDaemon = GetBoolArg("-daemon", false);
- if (fDaemon)
+ if (!AppInitParameterInteraction())
{
+ // InitError will have been called with detailed error, which ends up on console
+ exit(EXIT_FAILURE);
+ }
+ if (!AppInitSanityChecks())
+ {
+ // InitError will have been called with detailed error, which ends up on console
+ exit(EXIT_FAILURE);
+ }
+ if (GetBoolArg("-daemon", false))
+ {
+#if HAVE_DECL_DAEMON
fprintf(stdout, "Bitcoin server starting\n");
// Daemonize
- pid_t pid = fork();
- if (pid < 0)
- {
- fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
+ if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
+ fprintf(stderr, "Error: daemon() failed: %s\n", strerror(errno));
return false;
}
- if (pid > 0) // Parent process, pid is child process id
- {
- return true;
- }
- // Child process falls through to rest of initialization
-
- pid_t sid = setsid();
- if (sid < 0)
- fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
+#else
+ fprintf(stderr, "Error: -daemon is not supported on this operating system\n");
+ return false;
+#endif // HAVE_DECL_DAEMON
}
-#endif
- SoftSetBoolArg("-server", true);
- // Set this early so that parameter interactions go to console
- InitLogging();
- InitParameterInteraction();
- fRet = AppInit2(threadGroup, scheduler);
+ fRet = AppInitMain(threadGroup, scheduler);
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInit()");
@@ -187,5 +193,5 @@ int main(int argc, char* argv[])
// Connect bitcoind signal handlers
noui_connect();
- return (AppInit(argc, argv) ? 0 : 1);
+ return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
}
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 5c4c3bd274..ee2c654980 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -10,22 +10,22 @@
#include "random.h"
#include "streams.h"
#include "txmempool.h"
-#include "main.h"
+#include "validation.h"
#include "util.h"
#include <unordered_map>
#define MIN_TRANSACTION_BASE_SIZE (::GetSerializeSize(CTransaction(), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS))
-CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block) :
+CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID) :
nonce(GetRand(std::numeric_limits<uint64_t>::max())),
shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) {
FillShortTxIDSelector();
//TODO: Use our mempool prior to block acceptance to predictively fill more than just the coinbase
prefilledtxn[0] = {0, block.vtx[0]};
for (size_t i = 1; i < block.vtx.size(); i++) {
- const CTransaction& tx = block.vtx[i];
- shorttxids[i - 1] = GetShortID(tx.GetHash());
+ const CTransaction& tx = *block.vtx[i];
+ shorttxids[i - 1] = GetShortID(fUseWTXID ? tx.GetWitnessHash() : tx.GetHash());
}
}
@@ -47,7 +47,7 @@ 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)
@@ -59,10 +59,10 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
int32_t lastprefilledindex = -1;
for (size_t i = 0; i < cmpctblock.prefilledtxn.size(); i++) {
- if (cmpctblock.prefilledtxn[i].tx.IsNull())
+ if (cmpctblock.prefilledtxn[i].tx->IsNull())
return READ_STATUS_INVALID;
- lastprefilledindex += cmpctblock.prefilledtxn[i].index + 1; //index is a uint16_t, so cant overflow here
+ lastprefilledindex += cmpctblock.prefilledtxn[i].index + 1; //index is a uint16_t, so can't overflow here
if (lastprefilledindex > std::numeric_limits<uint16_t>::max())
return READ_STATUS_INVALID;
if ((uint32_t)lastprefilledindex > cmpctblock.shorttxids.size() + i) {
@@ -71,11 +71,11 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
// have neither a prefilled txn or a shorttxid!
return READ_STATUS_INVALID;
}
- txn_available[lastprefilledindex] = std::make_shared<CTransaction>(cmpctblock.prefilledtxn[i].tx);
+ txn_available[lastprefilledindex] = cmpctblock.prefilledtxn[i].tx;
}
prefilled_count = cmpctblock.prefilledtxn.size();
- // Calculate map of txids -> positions and check mempool to see what we have (or dont)
+ // Calculate map of txids -> positions and check mempool to see what we have (or don't)
// Because well-formed cmpctblock messages will have a (relatively) uniform distribution
// of short IDs, any highly-uneven distribution of elements can be safely treated as a
// READ_STATUS_FAILED.
@@ -104,6 +104,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 +131,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(), cmpctblock.GetSerializeSize(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;
}
@@ -142,8 +175,9 @@ bool PartiallyDownloadedBlock::IsTxAvailable(size_t index) const {
return txn_available[index] ? true : false;
}
-ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<CTransaction>& vtx_missing) const {
+ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing) {
assert(!header.IsNull());
+ uint256 hash = header.GetHash();
block = header;
block.vtx.resize(txn_available.size());
@@ -154,8 +188,13 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
return READ_STATUS_INVALID;
block.vtx[i] = vtx_missing[tx_missing_offset++];
} else
- block.vtx[i] = *txn_available[i];
+ block.vtx[i] = std::move(txn_available[i]);
}
+
+ // Make sure we can't call FillBlock again.
+ header.SetNull();
+ txn_available.clear();
+
if (vtx_missing.size() != tx_missing_offset)
return READ_STATUS_INVALID;
@@ -167,13 +206,14 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
// check its own merkle root and cache that check.
if (state.CorruptionPossible())
return READ_STATUS_FAILED; // Possible Short ID collision
- return READ_STATUS_INVALID;
+ return READ_STATUS_CHECKBLOCK_FAILED;
}
- LogPrint("cmpctblock", "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool and %lu txn requested\n", header.GetHash().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 CTransaction& tx : vtx_missing)
- LogPrint("cmpctblock", "Reconstructed block %s required tx %s\n", header.GetHash().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 b980e9e286..5a1d80d421 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -14,14 +14,14 @@ class CTxMemPool;
// Dumb helper to handle CTransaction compression at serialize-time
struct TransactionCompressor {
private:
- CTransaction& tx;
+ CTransactionRef& tx;
public:
- TransactionCompressor(CTransaction& txIn) : tx(txIn) {}
+ TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(tx); //TODO: Compress tx encoding
}
};
@@ -35,7 +35,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(blockhash);
uint64_t indexes_size = (uint64_t)indexes.size();
READWRITE(COMPACTSIZE(indexes_size));
@@ -53,11 +53,11 @@ public:
}
uint16_t offset = 0;
- for (size_t i = 0; i < indexes.size(); i++) {
- if (uint64_t(indexes[i]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())
+ for (size_t j = 0; j < indexes.size(); j++) {
+ if (uint64_t(indexes[j]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())
throw std::ios_base::failure("indexes overflowed 16 bits");
- indexes[i] = indexes[i] + offset;
- offset = indexes[i] + 1;
+ indexes[j] = indexes[j] + offset;
+ offset = indexes[j] + 1;
}
} else {
for (size_t i = 0; i < indexes.size(); i++) {
@@ -72,7 +72,7 @@ class BlockTransactions {
public:
// A BlockTransactions message
uint256 blockhash;
- std::vector<CTransaction> txn;
+ std::vector<CTransactionRef> txn;
BlockTransactions() {}
BlockTransactions(const BlockTransactionsRequest& req) :
@@ -81,7 +81,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(blockhash);
uint64_t txn_size = (uint64_t)txn.size();
READWRITE(COMPACTSIZE(txn_size));
@@ -99,17 +99,17 @@ 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
uint16_t index;
- CTransaction tx;
+ CTransactionRef tx;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
uint64_t idx = index;
READWRITE(COMPACTSIZE(idx));
if (idx > std::numeric_limits<uint16_t>::max())
@@ -124,6 +124,8 @@ typedef enum ReadStatus_t
READ_STATUS_OK,
READ_STATUS_INVALID, // Invalid object, peer is sending bogus crap
READ_STATUS_FAILED, // Failed to process object
+ READ_STATUS_CHECKBLOCK_FAILED, // Used only by FillBlock to indicate a
+ // failure in CheckBlock.
} ReadStatus;
class CBlockHeaderAndShortTxIDs {
@@ -146,7 +148,7 @@ public:
// Dummy for deserialization
CBlockHeaderAndShortTxIDs() {}
- CBlockHeaderAndShortTxIDs(const CBlock& block);
+ CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID);
uint64_t GetShortID(const uint256& txhash) const;
@@ -155,7 +157,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(header);
READWRITE(nonce);
@@ -191,16 +193,17 @@ public:
class PartiallyDownloadedBlock {
protected:
- std::vector<std::shared_ptr<const CTransaction> > txn_available;
- size_t prefilled_count = 0, mempool_count = 0;
+ std::vector<CTransactionRef> txn_available;
+ size_t prefilled_count = 0, mempool_count = 0, extra_count = 0;
CTxMemPool* pool;
public:
CBlockHeader header;
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<CTransaction>& vtx_missing) const;
+ ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
};
#endif
diff --git a/src/bloom.cpp b/src/bloom.cpp
index fd328e8e96..ac3e565721 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -19,23 +19,21 @@
#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
#define LN2 0.6931471805599453094172321214581765680755001343602552
-using namespace std;
-
CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, 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
* See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
*/
isFull(false),
- isEmpty(false),
- nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
+ isEmpty(true),
+ nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
nTweak(nTweakIn),
nFlags(nFlagsIn)
{
@@ -58,7 +56,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 +73,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 +103,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);
}
@@ -154,7 +152,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 +166,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));
@@ -189,7 +187,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;
@@ -256,8 +254,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,8 +278,8 @@ void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
void CRollingBloomFilter::insert(const uint256& hash)
{
- vector<unsigned char> data(hash.begin(), hash.end());
- insert(data);
+ std::vector<unsigned char> vData(hash.begin(), hash.end());
+ insert(vData);
}
bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
@@ -300,8 +298,8 @@ bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
bool CRollingBloomFilter::contains(const uint256& hash) const
{
- vector<unsigned char> data(hash.begin(), hash.end());
- return contains(data);
+ std::vector<unsigned char> vData(hash.begin(), hash.end());
+ return contains(vData);
}
void CRollingBloomFilter::reset()
diff --git a/src/bloom.h b/src/bloom.h
index ad6de625d8..5ad727c330 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -73,7 +73,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vData);
READWRITE(nHashFuncs);
READWRITE(nTweak);
diff --git a/src/chain.cpp b/src/chain.cpp
index 77e924e703..a5b369c4fc 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -1,12 +1,10 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// 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 "chain.h"
-using namespace std;
-
/**
* CChain implementation
*/
@@ -61,6 +59,13 @@ const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
return pindex;
}
+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);
+}
+
/** Turn the lowest '1' bit in the binary representation of a number into a '0'. */
int static inline InvertLowestOne(int n) { return n & (n - 1); }
diff --git a/src/chain.h b/src/chain.h
index 76a774c123..de120d2d75 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -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:
@@ -28,7 +42,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(VARINT(nBlocks));
READWRITE(VARINT(nSize));
READWRITE(VARINT(nUndoSize));
@@ -76,7 +90,7 @@ struct CDiskBlockPos
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(VARINT(nFile));
READWRITE(VARINT(nPos));
}
@@ -137,15 +151,15 @@ enum BlockStatus: uint32_t {
BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
- BLOCK_HAVE_DATA = 8, //! full block available in blk*.dat
- BLOCK_HAVE_UNDO = 16, //! undo data available in rev*.dat
+ BLOCK_HAVE_DATA = 8, //!< full block available in blk*.dat
+ BLOCK_HAVE_UNDO = 16, //!< undo data available in rev*.dat
BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO,
- BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed
- BLOCK_FAILED_CHILD = 64, //! descends from failed block
+ BLOCK_FAILED_VALID = 32, //!< stage after last reached validness failed
+ BLOCK_FAILED_CHILD = 64, //!< descends from failed block
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
- BLOCK_OPT_WITNESS = 128, //! block data in blk*.data was received with a witness-enforcing client
+ BLOCK_OPT_WITNESS = 128, //!< block data in blk*.data was received with a witness-enforcing client
};
/** The block chain is a tree shaped structure starting with the
@@ -200,7 +214,10 @@ public:
unsigned int nNonce;
//! (memory only) Sequential id assigned to distinguish order in which blocks are received.
- uint32_t nSequenceId;
+ int32_t nSequenceId;
+
+ //! (memory only) Maximum nTime in the chain upto and including this block.
+ unsigned int nTimeMax;
void SetNull()
{
@@ -216,6 +233,7 @@ public:
nChainTx = 0;
nStatus = 0;
nSequenceId = 0;
+ nTimeMax = 0;
nVersion = 0;
hashMerkleRoot = uint256();
@@ -281,6 +299,11 @@ public:
return (int64_t)nTime;
}
+ int64_t GetBlockTimeMax() const
+ {
+ return (int64_t)nTimeMax;
+ }
+
enum { nMedianTimeSpan=11 };
int64_t GetMedianTimePast() const
@@ -357,9 +380,10 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
- READWRITE(VARINT(nVersion));
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ int _nVersion = s.GetVersion();
+ if (!(s.GetType() & SER_GETHASH))
+ READWRITE(VARINT(_nVersion));
READWRITE(VARINT(nHeight));
READWRITE(VARINT(nStatus));
@@ -459,6 +483,9 @@ public:
/** Find the last common block between this chain and a block index entry. */
const CBlockIndex *FindFork(const CBlockIndex *pindex) const;
+
+ /** Find the earliest block with timestamp equal or greater than the given. */
+ CBlockIndex* FindEarliestAtLeast(int64_t nTime) const;
};
#endif // BITCOIN_CHAIN_H
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 86bef1e105..5055fb3e0a 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -31,7 +31,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi
genesis.nBits = nBits;
genesis.nNonce = nNonce;
genesis.nVersion = nVersion;
- genesis.vtx.push_back(txNew);
+ genesis.vtx.push_back(MakeTransactionRef(std::move(txNew)));
genesis.hashPrevBlock.SetNull();
genesis.hashMerkleRoot = BlockMerkleRoot(genesis);
return genesis;
@@ -55,6 +55,12 @@ static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits
return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
}
+void CChainParams::UpdateBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)
+{
+ consensus.vDeployments[d].nStartTime = nStartTime;
+ consensus.vDeployments[d].nTimeout = nTimeout;
+}
+
/**
* Main network
*/
@@ -71,11 +77,10 @@ public:
CMainParams() {
strNetworkID = "main";
consensus.nSubsidyHalvingInterval = 210000;
- consensus.nMajorityEnforceBlockUpgrade = 750;
- consensus.nMajorityRejectBlockOutdated = 950;
- consensus.nMajorityWindow = 1000;
consensus.BIP34Height = 227931;
consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
+ consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
+ consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
@@ -92,10 +97,16 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
- // Deployment of SegWit (BIP141 and BIP143)
+ // Deployment of SegWit (BIP141, BIP143, and BIP147)
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 0; // Never / undefined
+ consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1479168000; // November 15th, 2016.
+ consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017.
+
+ // The best chain should have at least this much work.
+ consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000003f94d1ad391682fe038bf5");
+
+ // By default assume that the signatures in ancestors of this block are valid.
+ consensus.defaultAssumeValid = uint256S("0x00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90"); //453354
/**
* The message start string is designed to be unlikely to occur in normal data.
@@ -114,12 +125,13 @@ public:
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
- vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be", true)); // Pieter Wuille
- vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me")); // Matt Corallo
+ // 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")); // Christian Decker
- vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); // Jeff Garzik
- vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch")); // Jonas Schnelli
+ vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com", true)); // Christian Decker, supports x1 - xf
+ vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli, only supports x1, x5, x9, and xd
+ vSeeds.push_back(CDNSSeedData("petertodd.org", "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);
@@ -129,11 +141,9 @@ public:
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
- fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
- fTestnetToBeDeprecatedFieldRPC = false;
checkpointData = (CCheckpointData) {
boost::assign::map_list_of
@@ -149,15 +159,18 @@ public:
(225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932"))
(250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"))
(279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40"))
- (295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")),
- 1397080064, // * UNIX timestamp of last checkpoint block
- 36544669, // * total number of transactions between genesis and last checkpoint
+ (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
// (the tx=... number in the SetBestChain debug.log lines)
- 60000.0 // * estimated number of transactions per day after checkpoint
+ 3.2 // * estimated number of transactions per second after that timestamp
};
}
};
-static CMainParams mainParams;
/**
* Testnet (v3)
@@ -167,11 +180,10 @@ public:
CTestNetParams() {
strNetworkID = "test";
consensus.nSubsidyHalvingInterval = 210000;
- consensus.nMajorityEnforceBlockUpgrade = 51;
- consensus.nMajorityRejectBlockOutdated = 75;
- consensus.nMajorityWindow = 100;
consensus.BIP34Height = 21111;
consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
+ consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
+ consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
@@ -188,11 +200,17 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1456790400; // March 1st, 2016
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
- // Deployment of SegWit (BIP141 and BIP143)
+ // Deployment of SegWit (BIP141, BIP143, and BIP147)
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1462060800; // May 1st 2016
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017
+ // The best chain should have at least this much work.
+ consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000001f057509eba81aed91");
+
+ // By default assume that the signatures in ancestors of this block are valid.
+ consensus.defaultAssumeValid = uint256S("0x00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc"); //1079274
+
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
pchMessageStart[2] = 0x09;
@@ -221,23 +239,25 @@ public:
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
- fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = false;
fMineBlocksOnDemand = false;
- fTestnetToBeDeprecatedFieldRPC = true;
+
checkpointData = (CCheckpointData) {
boost::assign::map_list_of
( 546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")),
- 1337966069,
- 1488,
- 300
+ };
+
+ chainTxData = ChainTxData{
+ // Data as of block 00000000c2872f8f8a8935c8e3c5862be9038c97d4de2cf37ed496991166928a (height 1063660)
+ 1483546230,
+ 12834668,
+ 0.15
};
}
};
-static CTestNetParams testNetParams;
/**
* Regression test
@@ -247,11 +267,10 @@ public:
CRegTestParams() {
strNetworkID = "regtest";
consensus.nSubsidyHalvingInterval = 150;
- consensus.nMajorityEnforceBlockUpgrade = 750;
- consensus.nMajorityRejectBlockOutdated = 950;
- consensus.nMajorityWindow = 1000;
- consensus.BIP34Height = -1; // BIP34 has not necessarily activated on regtest
+ consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)
consensus.BIP34Hash = uint256();
+ consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)
+ consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests)
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
@@ -269,6 +288,12 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 999999999999ULL;
+ // The best chain should have at least this much work.
+ consensus.nMinimumChainWork = uint256S("0x00");
+
+ // By default assume that the signatures in ancestors of this block are valid.
+ consensus.defaultAssumeValid = uint256S("0x00");
+
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
@@ -284,19 +309,21 @@ 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;
- fTestnetToBeDeprecatedFieldRPC = false;
checkpointData = (CCheckpointData){
boost::assign::map_list_of
- ( 0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")),
+ ( 0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"))
+ };
+
+ chainTxData = ChainTxData{
0,
0,
0
};
+
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
@@ -304,30 +331,33 @@ public:
base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container<std::vector<unsigned char> >();
}
};
-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 UpdateBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)
+{
+ globalChainParams->UpdateBIP9Parameters(d, nStartTime, nTimeout);
}
diff --git a/src/chainparams.h b/src/chainparams.h
index 638893e9ad..e5312d1080 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -11,6 +11,7 @@
#include "primitives/block.h"
#include "protocol.h"
+#include <memory>
#include <vector>
struct CDNSSeedData {
@@ -28,9 +29,12 @@ typedef std::map<int, uint256> MapCheckpoints;
struct CCheckpointData {
MapCheckpoints mapCheckpoints;
- int64_t nTimeLastCheckpoint;
- int64_t nTransactionsLastCheckpoint;
- double fTransactionsPerDay;
+};
+
+struct ChainTxData {
+ int64_t nTime;
+ int64_t nTxCount;
+ double dTxRate;
};
/**
@@ -58,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 */
@@ -67,14 +69,14 @@ public:
uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }
/** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
- /** In the future use NetworkIDString() for RPC fields */
- bool TestnetToBeDeprecatedFieldRPC() const { return fTestnetToBeDeprecatedFieldRPC; }
/** Return the BIP70 network string (main, test or regtest) */
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::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData& Checkpoints() const { return checkpointData; }
+ const ChainTxData& TxData() const { return chainTxData; }
+ void UpdateBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout);
protected:
CChainParams() {}
@@ -87,24 +89,25 @@ protected:
std::string strNetworkID;
CBlock genesis;
std::vector<SeedSpec6> vFixedSeeds;
- bool fMiningRequiresPeers;
bool fDefaultConsistencyChecks;
bool fRequireStandard;
bool fMineBlocksOnDemand;
- bool fTestnetToBeDeprecatedFieldRPC;
CCheckpointData checkpointData;
+ ChainTxData chainTxData;
};
/**
- * 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.
@@ -112,4 +115,9 @@ CChainParams& Params(const std::string& chain);
*/
void SelectParams(const std::string& chain);
+/**
+ * Allows modifying the BIP9 regtest parameters.
+ */
+void UpdateBIP9Parameters(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..43c9a13c54 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
@@ -63,31 +61,30 @@ public:
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()
@@ -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..396a411689 100644
--- a/src/chainparamsseeds.h
+++ b/src/chainparamsseeds.h
@@ -8,943 +8,1174 @@
* 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,0x02,0x07,0x08,0x0c}, 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,0x05,0x27,0x40,0x07}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x2d,0x50,0x22}, 38333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x33,0xa0,0x26}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x3d,0x21,0x21}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x3d,0x25,0x0c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x5f,0x50,0x2f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x66,0xa4,0xad}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xaf,0x47,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xbd,0xa5,0x16}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xc7,0x82,0xe4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xe4,0x64,0xde}, 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,0x0d,0x5d,0x06,0x85}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0x55,0x22,0x0a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0xf1,0x00,0x3f}, 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,0xf8,0x71,0x34}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xfd,0x97,0x49}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x04,0x60,0x79}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x45,0x41,0xbf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x57,0x08,0x2b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x96,0xe0,0x6e}, 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,0x1b,0x00,0xeb,0x21}, 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,0x1f,0xb8,0xc5,0x60}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xd6,0xf0,0x38}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x01,0xca,0x86}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x12,0x4a,0xe8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x22,0x30,0x11}, 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,0xa4,0x10}, 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,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,0x25,0x8f,0x09,0x80}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x99,0xac,0xe3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xc1,0xe3,0x10}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xcd,0x08,0x4e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xdc,0x00,0x72}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xe8,0xda,0xc7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x26,0x8c,0xa1,0x35}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x28,0x57,0x46,0x78}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x29,0xa2,0xa3,0x5d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2a,0x02,0xc6,0x30}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x14,0x43,0x01}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x37,0xc5,0x4d}, 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,0x3a,0x26,0xa2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x3f,0x01,0x21}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x4f,0x02,0x46}, 8333},
+ {{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,0x13,0x89,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x1c,0xce,0x92}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x20,0xfc,0xc5}, 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,0x3b,0x27,0xc3}, 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,0xa0,0xc3,0x79}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xa6,0x8e,0x15}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xa6,0xa0,0x1d}, 8330},
+ {{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,0x64,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x59,0xc0,0x86}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0xb9,0xc2,0xa0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0xbd,0x81,0xda}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x31,0x41,0x02,0x8c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x03,0x48,0x81}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x1f,0x63,0xe1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x33,0xaf,0x21,0x5f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0x01,0xa5,0xdb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0x0a,0xaa,0xba}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0x33,0x80,0xd8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xc5,0x82,0xf4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0x3b,0x02,0x16}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0x54,0x06,0x51}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3b,0x7d,0x08,0x8f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3b,0xa7,0x82,0x8b}, 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,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,0x4c,0x60,0x06}, 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,0x85,0x0f,0x3a}, 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,0x85,0xc2,0x9c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x8a,0x01,0x5f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd8,0xee,0x03}, 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,0x3f,0x89,0x28,0xcf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0xe7,0x60,0x6d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x4e,0xf0,0x96}, 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,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,0x40,0x89,0xec,0x44}, 8833},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x9c,0xc1,0x78}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x4f,0xa0,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x5b,0xe6,0xe7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x87,0x80,0x79}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xac,0x0a,0x04}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xc2,0x26,0xfa}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xc2,0x26,0xfd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,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,0xd7,0x22,0x1a}, 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,0x43,0xcd,0x60,0x6c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xcd,0x80,0x05}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xdb,0xe9,0x8c}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,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,0x44,0x64,0xc4,0x76}, 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,0xa8,0x76,0xea}, 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,0x1e,0xe5,0x0a}, 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,0x45,0x7d,0xc1,0x91}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0xa2,0x8b,0x7d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x23,0x62,0x27}, 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,0x47,0x7e,0xb5,0x92}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xb4,0x20,0x69}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0xe2,0x40,0x91}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x53,0x8c,0xf2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x54,0x80,0x9e}, 9333},
+ {{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,0x4a,0xd7,0x85,0x91}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x4c,0x65,0xa9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x55,0x0d,0x08}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x56,0xa8,0x0d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0xaa,0x61,0x19}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0xb1,0x89,0x86}, 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,0x4d,0x35,0x88,0x06}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x6e,0x0b,0x34}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x19,0x20,0xce}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x22,0x08,0x78}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x2e,0x20,0x63}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x38,0x09,0xd6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x38,0xe5,0xb1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x81,0xed,0xf5}, 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,0x4f,0xac,0xc2,0xdb}, 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,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,0x50,0x59,0x89,0x73}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x5d,0x24,0xad}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x65,0xa7,0x64}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x72,0x22,0x9e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x7f,0x88,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xbc,0x8b,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xde,0x27,0x4d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xdf,0x69,0x45}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xe5,0x97,0xbb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xf0,0x81,0xdd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x07,0x0a,0xee}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x07,0x0d,0x54}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x1b,0x60,0x5c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x23,0x8f,0x62}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x52,0xc9,0x05}, 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,0xa9,0xe3,0x24}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xab,0x02,0x77}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xab,0x26,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xaf,0xff,0x76}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xcf,0x08,0x31}, 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,0x09,0x01,0x4d}, 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,0x52,0x66,0x0d,0x75}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x74,0xcb,0xf0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x82,0x67,0x10}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x88,0x41,0xe3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x9e,0xe3,0xee}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc5,0xd4,0x19}, 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,0xcc,0x29}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc8,0xcc,0x77}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x69,0xdf}, 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,0x52,0xdd,0x6f,0x88}, 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,0x53,0x89,0x29,0x0a}, 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,0x53,0xa9,0x02,0x2b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xd9,0xcb,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xf9,0x58,0x34}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x1a,0xa2,0x5c}, 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,0x54,0x86,0xc2,0x73}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xc9,0x20,0x73}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd4,0xe8,0x47}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xee,0x8c,0xb0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x0a,0x68,0x22}, 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,0x90,0x4f,0xbe}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x91,0xe4,0xc0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xc2,0xee,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xe4,0xc9,0x50}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xe5,0xe4,0xae}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xec,0xe9,0x57}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x50,0xcc,0xb9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x69,0xe3,0xbe}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x87,0x27,0x28}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x6a,0x8b,0x7f}, 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,0xef,0x65,0x66}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xf3,0xc5,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x70,0x70,0xad}, 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,0xb9,0x9b,0x86}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xca,0xca,0xdd}, 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,0x58,0xd0,0x27,0xb6}, 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,0xa3,0xe0,0xbb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xa9,0xe9,0x96}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xb8,0x41,0x55}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xd4,0x5b,0xdb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xf9,0xb2,0x24}, 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,0x5b,0x41,0x61,0x9d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x6b,0x40,0x8f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x72,0x23,0x6b}, 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,0x91,0x6e,0x5f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x9d,0x26,0x97}, 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,0xcd,0xb0,0x36}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xce,0xcb,0x0a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xce,0xcb,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xd7,0x23,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xdb,0xef,0x9f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xdf,0x85,0x02}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xdf,0x85,0x28}, 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,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,0x59,0x43,0xcf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0xdd,0xc9,0x8a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x5f,0xbb,0x7a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x67,0x49,0xbb}, 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,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,0x5d,0xbe,0x45,0xf2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x13,0x0c,0xf4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x9c,0x80,0x74}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xb1,0xab,0x49}, 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,0xed,0x1a,0xad}, 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,0x5e,0xff,0x80,0x62}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x4f,0x23,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x5b,0x29,0x27}, 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,0x5f,0x80,0x30,0xd1}, 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,0x60,0x17,0x43,0x55}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x61,0x40,0xb1,0x0a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x61,0x68,0xc9,0x5f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0x1d,0xc5,0x95}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0xa9,0x02,0x6b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x63,0xe8,0x30,0x48}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x65,0x64,0x8d,0x37}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x07,0x20,0x28}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x35,0xe1,0x45}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xf9,0x6a,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x80,0xe0,0x0d}, 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,0x9b,0x01,0x9e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xa8,0x80,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc7,0xa0,0xe4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xcc,0x6d,0x0b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xdb,0xfb,0x76}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xdf,0x03,0x81}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xdf,0x03,0xdb}, 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,0x68,0xf5,0x63,0xe3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6a,0x26,0xea,0x59}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6a,0x68,0x86,0xda}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x88,0x06,0x47}, 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,0x97,0x90,0x67}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xaa,0x2c,0x63}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xb5,0x89,0x85}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xbf,0x66,0x0d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x3a,0xfc,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x3b,0x09,0xa7}, 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,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,0x6c,0xa2,0x6a,0xd7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xa8,0x85,0xa4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xad,0xca,0x65}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xb4,0x6e,0xbe}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x1d,0x4b,0x28}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x78,0xc2,0x88}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xe6,0xe6,0x58}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xeb,0x43,0x73}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xeb,0x45,0x78}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xec,0x5a,0xc7}, 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,0x6e,0x0a,0x82,0x0c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6e,0x0a,0xb0,0x5e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6e,0x84,0xac,0xfb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6f,0x5a,0x9e,0x11}, 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,0x74,0x1f,0x7b,0x8b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0xc0,0x30,0x2e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0xc1,0xa4,0x62}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0x1d,0x9c,0xe7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0x3f,0x2c,0x85}, 19980},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0x51,0x63,0x1b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0x6a,0x0c,0xa9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0x93,0x89,0x9b}, 19980},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0xb9,0x01,0xb6}, 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,0x79,0xfe,0xad,0x17}, 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,0x38,0x81,0x2d}, 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,0x7b,0xce,0x20,0xc6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7c,0xbd,0xa0,0xdd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7c,0xbd,0xc0,0xe8}, 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,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,0x80,0xc7,0x44,0xcd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x82,0xea,0xcf,0x73}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0x71,0x29,0x7b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0x72,0x48,0x68}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x84,0xcc,0x6c,0x9b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0x77,0x0d,0xe6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0xd5,0x85,0xce}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0xd5,0x85,0xcf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x87,0x17,0x05,0x03}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x89,0x4a,0x00,0x42}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8a,0x44,0x01,0x2d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8a,0x44,0x02,0xc2}, 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,0x8a,0x44,0x40,0x1c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8b,0x3b,0x2a,0xf8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8b,0xdc,0xf0,0x99}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8c,0x70,0x6b,0x76}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8c,0xba,0xe0,0x70}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8d,0x34,0x40,0x8d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8e,0x44,0xed,0x6b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8e,0xd9,0x0c,0x6a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x92,0x3c,0xcc,0x5c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x92,0xb9,0xa1,0xd1}, 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,0x95,0xd2,0x85,0xf4}, 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,0x97,0xe7,0xee,0x19}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x97,0xf8,0xa0,0xe3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x99,0xe6,0xe4,0x0f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9b,0x85,0x2b,0xf9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0x3a,0xee,0x91}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0x6d,0x4f,0x0d}, 34821},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9f,0xcb,0x46,0xd0}, 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,0xd8,0xc0,0xe7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf3,0x64,0x6f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf6,0x0b,0xc2}, 8333},
{{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,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,0xa2,0xfc,0x2e,0x53}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa3,0xac,0x21,0x4e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa3,0xac,0xc2,0x1e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa9,0xe5,0xc6,0x6a}, 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,0x67,0xcd,0xc5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0xf5,0xe1,0x7e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xb3,0x25,0x08}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd0,0xcb,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xfc,0x2e,0x10}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x75,0x8d,0x7c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaf,0x7e,0x26,0x9e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaf,0x7e,0x26,0xb1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaf,0x8b,0x6a,0x77}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaf,0x8c,0xe8,0x42}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x09,0x75,0x64}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x24,0x21,0x79}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x24,0x63,0xde}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x38,0xe3,0x24}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x64,0x64,0xce}, 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,0xb0,0x7b,0x07,0x94}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x7e,0xa7,0x0a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0xdf,0xc9,0xc6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0x44,0x3e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0x66,0x38}, 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,0x7c,0xc5,0x65}, 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,0x81,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xbc,0x2f,0x3e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xc7,0xf0,0x16}, 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,0xed,0x23,0x22}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xee,0xe0,0xf2}, 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,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,0xb3,0x2b,0xb7,0x02}, 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,0xb6,0x5d,0x22,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x08,0xee,0xc5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x0b,0x8b,0xac}, 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,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,0xb9,0x18,0xe9,0x64}, 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,0x19,0x30,0x72}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1c,0x4c,0xb3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x46,0x69,0x98}, 8339},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x4d,0x80,0x45}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x4d,0x80,0xf1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x56,0x4f,0x57}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x59,0x66,0x02}, 3333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x59,0x66,0x35}, 3333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x6d,0x90,0x9b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x75,0x4b,0x32}, 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,0x80,0x29,0x9d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x82,0xe2,0x6a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x91,0x82,0x4c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x3f,0xc0,0x68}, 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,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,0xbc,0xd6,0x80,0x4d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0x0a,0x08,0xd3}, 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,0xbe,0x6f,0xe7,0x13}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x83,0x2c,0x5d}, 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,0xe3,0xf5,0x85}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xf1,0x4a,0x7b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xf1,0x4a,0x7e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xfe,0x47,0xde}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x0a,0x40,0x55}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x2e,0x50,0x65}, 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,0x5d,0x4f,0xd7}, 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,0xc1,0xef,0x50,0x9b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x3f,0x8c,0xd0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x57,0x01,0xe8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0xbb,0xe3,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0xf7,0x0c,0x88}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x5b,0xb0,0x56}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc4,0x1c,0x62,0x14}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x2c,0xf9,0x23}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x54,0xac,0xfc}, 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,0xc6,0xd3,0x61,0x2e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0x42,0x40,0xc6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0x65,0x64,0x3a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0x65,0x64,0x3b}, 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,0x2e,0xf1,0x47}, 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,0xcb,0x09,0xe1,0x0d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0xb1,0x8e,0x25}, 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,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,0xcd,0xd1,0x83,0x96}, 13838},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xce,0x35,0x40,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xce,0x48,0xc0,0x45}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xce,0x7b,0x70,0xb4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x42,0xd0,0x99}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x44,0xae,0x4c}, 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,0x6f,0x30,0x84}, 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,0x06,0xcd,0x7e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x28,0x60,0x79}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x3a,0x82,0x89}, 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,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,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,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,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,0xd1,0x7e,0x45,0xf3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x7e,0x6c,0x5b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xc3,0x04,0x12}, 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,0x36,0x25,0xe1}, 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,0x95,0xea,0x6d}, 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,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,0xd4,0xca,0x84,0x11}, 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,0xa5,0x44,0xda}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xc4,0xc8,0xd5}, 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,0x4a,0x20,0x6d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x9e,0xe1,0x46}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xa4,0x8a,0x0d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xa7,0xec,0xf7}, 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,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,0x0c,0xc7,0xcf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x14,0x82,0x48}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x06,0x94}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x8c,0x67}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x1c,0x60,0xb4}, 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,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},
+ {{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,0xd1,0x20,0xdb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xda,0xa1,0x21,0xa5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdd,0x79,0x90,0x8a}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x20,0x48,0x3a,0x84,0xbb,0x91,0xe8,0x46}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x20,0x66,0x0e,0x9e,0xb4,0x89,0xf8,0xb8}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x38,0x54,0x12,0x11,0xb5,0xac,0xa9,0x6b}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x04,0xe3,0x1f,0x66,0xcd,0x4c,0x82,0x9f}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x00,0xad,0x01,0xf4,0x9e,0xa9,0xfa,0x2e}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x00,0xe5,0x0b,0xaa,0xb6,0x6f,0xf4,0x18}, 8333},
+ {{0x20,0x01,0x00,0x00,0x53,0xaa,0x06,0x4c,0x20,0xa2,0x59,0xc4,0xad,0x22,0x93,0xea}, 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,0x20,0x0f,0x3a,0xe5,0x3c,0xbc,0x74,0xc9}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x38,0xf2,0x13,0xb4,0xb2,0x08,0x56,0x04}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x20,0x0b,0x22,0xa7,0xcc,0x50,0xf5,0x2d}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x24,0xef,0x1a,0xef,0xa9,0x94,0x30,0x3d}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x24,0xfc,0x0b,0x5d,0xad,0x4f,0x4d,0xb2}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x28,0xbf,0x2d,0x23,0xe0,0x2e,0xc3,0xef}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x3c,0xd0,0x3c,0x2e,0xda,0x44,0xa7,0x59}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x08,0x7e,0x0f,0xd7,0xb1,0xc2,0x01,0xb4}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x18,0xdb,0x3b,0xda,0xab,0x90,0xe8,0x1e}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x04,0xe7,0x16,0x60,0x86,0x2f,0xa6,0xd7}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x00,0x06,0x00,0x2b,0x50,0x74,0x95,0x88}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x10,0xf8,0xa7,0xd7,0xbb,0x90,0xf5,0x24}, 8333},
+ {{0x20,0x01,0x13,0xd8,0x1c,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11}, 8333},
+ {{0x20,0x01,0x15,0xc0,0x65,0xff,0x06,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x16,0x08,0x00,0x10,0x01,0x56,0x00,0xae,0x00,0x00,0x00,0x00,0x4a,0xdb}, 8333},
+ {{0x20,0x01,0x16,0x20,0x0b,0x1b,0x88,0x88,0x02,0x0d,0xb9,0xff,0xfe,0x41,0x67,0x10}, 8333},
+ {{0x20,0x01,0x16,0x20,0x0b,0x1b,0xfa,0xce,0x02,0x0d,0xb9,0xff,0xfe,0x41,0x67,0x10}, 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},
+ {{0x20,0x01,0x16,0x80,0x01,0x01,0x01,0xae,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x16,0xd8,0xff,0x00,0x85,0xde,0x02,0x0c,0x29,0xff,0xfe,0x52,0x95,0x94}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x44,0x00,0x43,0x4d,0x54,0x00,0x00,0xff,0xfe,0x42,0x26,0x78}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x50,0x00,0x8c,0x8b,0x54,0x00,0x00,0xff,0xfe,0x1f,0xc0,0x23}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x50,0x00,0x8c,0xe6,0x54,0x00,0x00,0xff,0xfe,0x1b,0x24,0xa9}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x00,0x05,0x03,0x14,0x54,0x00,0x00,0xff,0xfe,0x2c,0x42,0xe8}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x00,0x05,0x05,0x1b,0x54,0x00,0x00,0xff,0xfe,0x49,0xfe,0x5b}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x00,0x05,0x00,0xbc,0x54,0x00,0x00,0xff,0xfe,0x3b,0x93,0x39}, 8333},
+ {{0x20,0x01,0x1a,0xf8,0x40,0x20,0xa0,0x20,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x1b,0xc8,0x01,0xa0,0x59,0x0e,0x02,0xe0,0xf4,0xff,0xfe,0x16,0x3a,0x39}, 8333},
+ {{0x20,0x01,0x1c,0x04,0x14,0x01,0x8f,0x00,0xf4,0xfe,0x4f,0xff,0xfe,0x0c,0xdf,0x40}, 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,0x28,0x61,0x35,0xe0,0x01,0x50,0x54,0x00,0xff,0xfe,0x37,0xe9,0xeb}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x10,0x00,0x10,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x10,0x00,0x14,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x10,0x04,0x22,0xae,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x10,0x04,0x29,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x10,0x08,0x11,0xe0,0x00,0x00,0x00,0x00,0x1a,0x5c,0x6d,0x9d}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x10,0x08,0x11,0xe0,0x00,0x00,0x00,0x00,0x0b,0x74,0xba,0xf7}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x10,0x08,0x23,0x7a,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,0x10,0x08,0x04,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 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,0xd0,0x00,0x01,0x56,0x30,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,0x80,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0x88,0x52,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,0xa5,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
{{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,0xd2,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xdb,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xdc,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xe1,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xef,0x5b,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,0x38,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x05,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
{{0x20,0x01,0x41,0xd0,0x00,0x02,0x9c,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x02,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,0xb7,0x92,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,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,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,0x03,0x03,0x04,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x1a,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x3f,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x46,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x4f,0x48,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,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,0x08,0x72,0xc2,0x00,0x0d,0x02,0x42,0xac,0x11,0x00,0x02}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x80,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xa7,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xbc,0xcc,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,0xc6,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xde,0x3d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xe2,0x57,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,0x14,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x15,0xb2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x1a,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x24,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x30,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x58,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x68,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x68,0x2d,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,0x0a,0xf5,0x2a,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,0x0e,0x13,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
{{0x20,0x01,0x41,0xd0,0x00,0x0e,0x02,0x6b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0e,0x0f,0x73,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,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,0x44,0x28,0x02,0x00,0x81,0x71,0x0d,0xb6,0x2f,0xf4,0x9c,0x0e,0xa2,0xda}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x07,0x15,0x1c,0xba,0xac,0x6f,0xff,0xfe,0xb7,0x3b,0xa9}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x0b,0x0a,0xd6,0x0a,0x60,0x6e,0xff,0xfe,0xc6,0x23,0x23}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x11,0x06,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0f}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x14,0x07,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x20,0x01,0x04,0x70,0x1f,0x14,0x00,0x7d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x20,0x01,0x04,0x70,0x00,0x27,0x00,0xce,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 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,0x0e,0x9b,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xef}, 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,0x27,0x01,0x9f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x27,0x06,0x65,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,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,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,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,0x72,0x7b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x14}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x07,0x02,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x07,0x00,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x7f,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x08,0x02,0xe1,0x58,0x25,0x39,0xdf,0x3e,0x4c,0x54,0xa8}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x08,0x02,0xe1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x08,0x02,0xe1,0xae,0x2a,0xe2,0x57,0x44,0x70,0x63,0x50}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x0a,0x0c,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 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,0x4b,0xa0,0xba,0xbe,0x08,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x4b,0xa0,0xca,0xfe,0x03,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x4b,0xa0,0xff,0xee,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10}, 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,0x06,0x78,0x01,0x74,0x40,0x21,0x00,0x00,0x00,0x00,0x00,0x02,0x83,0x33}, 8333},
+ {{0x20,0x01,0x06,0x7c,0x16,0xdc,0x12,0x01,0x50,0x54,0x00,0xff,0xfe,0x17,0x4d,0xac}, 8333},
+ {{0x20,0x01,0x06,0x7c,0x21,0x28,0xff,0xff,0x60,0x62,0x36,0xff,0xfe,0x30,0x65,0x32}, 8333},
+ {{0x20,0x01,0x06,0x7c,0x25,0x64,0x03,0x31,0x35,0x47,0x6e,0x28,0x85,0xa4,0xfb,0x27}, 8333},
+ {{0x20,0x01,0x06,0xa0,0x02,0x00,0x03,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x07,0x18,0x08,0x01,0x03,0x11,0x50,0x54,0x00,0xff,0xfe,0x19,0xc4,0x83}, 8333},
+ {{0x20,0x01,0x07,0xb8,0x02,0xff,0x00,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x08,0xd8,0x08,0xa6,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x08,0x6c}, 8333},
+ {{0x20,0x01,0x08,0xd8,0x09,0x23,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x0e,0xbd}, 8333},
+ {{0x20,0x01,0x09,0x60,0x06,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 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,0x01,0x0b,0xa8,0x01,0xf1,0xf0,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x0b,0xc8,0x22,0x5f,0x01,0x0e,0x05,0x05,0x65,0x73,0x75,0x73,0x0d,0x0a}, 8333},
+ {{0x20,0x01,0x0b,0xc8,0x27,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 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,0x01,0x0b,0xc8,0x3c,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}, 8333},
+ {{0x20,0x01,0x0b,0xc8,0x47,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x08,0x07}, 8333},
+ {{0x20,0x01,0x0e,0x42,0x01,0x02,0x18,0x05,0x01,0x60,0x00,0x16,0x02,0x06,0x00,0x31}, 8333},
+ {{0x20,0x02,0x12,0xf1,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xf1,0x00,0x3f}, 8333},
+ {{0x20,0x02,0x01,0xe2,0x53,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe2,0x53,0x49}, 8333},
+ {{0x20,0x02,0x01,0xe2,0x55,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe2,0x55,0x88}, 8333},
+ {{0x20,0x02,0x25,0x01,0xcf,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x01,0xcf,0x62}, 8333},
+ {{0x20,0x02,0x26,0x8c,0xa1,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x8c,0xa1,0x35}, 8333},
+ {{0x20,0x02,0x2a,0x33,0x99,0xdb,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0x33,0x99,0xdb}, 8332},
+ {{0x20,0x02,0x2e,0xbc,0x2c,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07}, 8333},
+ {{0x20,0x02,0x2f,0x59,0x2c,0x9c,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x59,0x2c,0x9c}, 11885},
+ {{0x20,0x02,0x2f,0x5a,0x36,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5a,0x36,0x19}, 8333},
+ {{0x20,0x02,0x2f,0x5a,0x36,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5a,0x36,0xa4}, 8333},
+ {{0x20,0x02,0x2f,0x5a,0x04,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5a,0x04,0x29}, 8333},
+ {{0x20,0x02,0x2f,0x5a,0x56,0x2a,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5a,0x56,0x2a}, 8333},
+ {{0x20,0x02,0x3a,0x3b,0x02,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x3a,0x3b,0x02,0x16}, 8333},
+ {{0x20,0x02,0x3d,0xfa,0x5d,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x3d,0xfa,0x5d,0x23}, 8333},
+ {{0x20,0x02,0x42,0x4f,0xa0,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x4f,0xa0,0x52}, 8333},
+ {{0x20,0x02,0x45,0x1e,0xe9,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x1e,0xe9,0x22}, 8333},
+ {{0x20,0x02,0x45,0x40,0x4b,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x40,0x4b,0x30}, 8333},
+ {{0x20,0x02,0x51,0xab,0x07,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xab,0x07,0xcc}, 8333},
+ {{0x20,0x02,0x05,0x27,0xde,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x27,0xde,0x11}, 8333},
+ {{0x20,0x02,0x53,0x95,0x7d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x95,0x7d,0x01}, 8333},
+ {{0x20,0x02,0x53,0x95,0x7d,0x2a,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x95,0x7d,0x2a}, 8333},
+ {{0x20,0x02,0x56,0x69,0xe3,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x69,0xe3,0xbe}, 8333},
+ {{0x20,0x02,0x56,0x6a,0x5d,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x6a,0x5d,0x6d}, 8333},
+ {{0x20,0x02,0x59,0xb9,0xf8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0xb9,0xf8,0x20}, 8333},
+ {{0x20,0x02,0x59,0xf8,0xac,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0xf8,0xac,0x69}, 8333},
+ {{0x20,0x02,0x5b,0xd4,0xb6,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xd4,0xb6,0x5a}, 8333},
+ {{0x20,0x02,0x5c,0x3f,0x39,0xdb,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x3f,0x39,0xdb}, 8333},
+ {{0x20,0x02,0x5d,0x33,0x8d,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,0x33,0x8d,0x03}, 8333},
+ {{0x20,0x02,0x5d,0x67,0x49,0xbb,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,0x67,0x49,0xbb}, 8333},
+ {{0x20,0x02,0x5d,0xae,0x5d,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,0xae,0x5d,0x5f}, 8333},
+ {{0x20,0x02,0x5d,0xbe,0x8c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,0xbe,0x8c,0xc6}, 8333},
+ {{0x20,0x02,0x5d,0xbe,0x95,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,0xbe,0x95,0x03}, 8333},
+ {{0x20,0x02,0x5f,0xd3,0x89,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xd3,0x89,0x44}, 8333},
+ {{0x20,0x02,0x5f,0xd3,0x94,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xd3,0x94,0x67}, 8333},
+ {{0x20,0x02,0x67,0xf9,0x6a,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0xf9,0x6a,0x48}, 8333},
+ {{0x20,0x02,0x67,0xf9,0x6a,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0xf9,0x6a,0x4a}, 8333},
+ {{0x20,0x02,0x67,0xf9,0x6a,0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0xf9,0x6a,0x95}, 8333},
+ {{0x20,0x02,0x6a,0x0e,0x3e,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x6a,0x0e,0x3e,0xa8}, 10011},
+ {{0x20,0x02,0x6b,0x96,0x37,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,0x6b,0x96,0x37,0x5a}, 8333},
+ {{0x20,0x02,0x6c,0xa8,0xcf,0xfb,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0xa8,0xcf,0xfb}, 8333},
+ {{0x20,0x02,0x6c,0xaf,0x02,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0xaf,0x02,0x34}, 8333},
+ {{0x20,0x02,0x6d,0xec,0x58,0xf5,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0xec,0x58,0xf5}, 8333},
+ {{0x20,0x02,0x6d,0xec,0x5a,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0xec,0x5a,0xc7}, 8333},
+ {{0x20,0x02,0x72,0x37,0x4a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0x37,0x4a,0x02}, 20033},
+ {{0x20,0x02,0x72,0x37,0x94,0xfd,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0x37,0x94,0xfd}, 10011},
+ {{0x20,0x02,0x72,0x37,0xe4,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0x37,0xe4,0x28}, 8333},
+ {{0x20,0x02,0x72,0x37,0xfc,0xf6,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0x37,0xfc,0xf6}, 20188},
+ {{0x20,0x02,0x76,0xc0,0x96,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xc0,0x96,0xe6}, 8333},
+ {{0x20,0x02,0x78,0x19,0x7e,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x19,0x7e,0x80}, 7743},
+ {{0x20,0x02,0x78,0x1a,0xea,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x1a,0xea,0x86}, 8333},
+ {{0x20,0x02,0x78,0x1a,0xf3,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x1a,0xf3,0xc2}, 14475},
+ {{0x20,0x02,0x78,0x4c,0xc2,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x4c,0xc2,0xc0}, 8333},
+ {{0x20,0x02,0x78,0x4c,0xec,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x4c,0xec,0x97}, 8333},
+ {{0x20,0x02,0x79,0x2b,0x26,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0x2b,0x26,0x1a}, 8333},
+ {{0x20,0x02,0x88,0xf3,0x8c,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0xf3,0x8c,0xca}, 8333},
+ {{0x20,0x02,0x88,0xf3,0xa8,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0xf3,0xa8,0x3c}, 8333},
+ {{0x20,0x02,0x8a,0xc9,0x51,0x6f,0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0xc9,0x51,0x6f}, 8333},
+ {{0x20,0x02,0x8b,0x81,0x6d,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x8b,0x81,0x6d,0x78}, 50344},
+ {{0x20,0x02,0x8b,0x81,0x6e,0x5c,0x00,0x00,0x00,0x00,0x00,0x00,0x8b,0x81,0x6e,0x5c}, 38176},
+ {{0x20,0x02,0x8b,0xc4,0x90,0xa6,0x00,0x00,0x00,0x00,0x00,0x00,0x8b,0xc4,0x90,0xa6}, 8333},
+ {{0x20,0x02,0xac,0x52,0xb8,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x52,0xb8,0x54}, 8333},
+ {{0x20,0x02,0xad,0xd0,0xc1,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0xd0,0xc1,0x4a}, 8333},
+ {{0x20,0x02,0xb0,0x7e,0xa7,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x7e,0xa7,0x0a}, 8333},
+ {{0x20,0x02,0xb2,0x7c,0xc5,0x65,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x50}, 8333},
+ {{0x20,0x02,0xb2,0x7c,0xc5,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x02,0xb9,0x4d,0x80,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0xb9,0x4d,0x80,0xf1}, 8333},
+ {{0x20,0x02,0xb9,0x82,0xe2,0x6a,0x00,0x00,0x00,0x00,0x00,0x00,0xb9,0x82,0xe2,0x6a}, 8333},
+ {{0x20,0x02,0xbc,0xd5,0x31,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0xd5,0x31,0x45}, 8333},
+ {{0x20,0x02,0xc0,0x8a,0xd2,0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x8a,0xd2,0x2b}, 8333},
+ {{0x20,0x02,0xc0,0xc7,0xf8,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc7,0xf8,0xe3}, 32771},
+ {{0x20,0x02,0xc1,0xa9,0xfc,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,0xc1,0xa9,0xfc,0x5a}, 8333},
+ {{0x20,0x02,0xc2,0x3f,0x8f,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0x3f,0x8f,0xc5}, 8333},
+ {{0x20,0x02,0xd3,0x95,0xea,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0xd3,0x95,0xea,0x6d}, 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},
+ {{0x20,0x02,0xd9,0x17,0x0e,0x91,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x17,0x0e,0x91}, 8333},
+ {{0x20,0x02,0xdb,0x71,0xf4,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0xdb,0x71,0xf4,0x34}, 8333},
+ {{0x24,0x00,0x26,0x51,0x01,0x61,0x10,0x00,0x68,0x47,0xd4,0x0f,0xaa,0xa3,0x48,0x48}, 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},
+ {{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,0x03,0x42,0x00,0x04,0x03,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff}, 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},
+ {{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},
+ {{0x24,0x0d,0x00,0x1a,0x03,0x02,0x86,0x00,0x88,0x76,0xa3,0x6d,0x12,0xee,0xf2,0x85}, 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,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},
{{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,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x91,0x6a,0x29}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xf1,0x1e,0xaa}, 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,0x28,0x14,0x45}, 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,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x89,0x11,0x6f}, 8333},
+ {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xb0,0x5f,0xc4}, 8333},
+ {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xe0,0x23,0x3e}, 8333},
+ {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xe0,0x00,0x51}, 8333},
+ {{0x26,0x00,0x88,0x05,0x24,0x00,0x01,0x4e,0x02,0x26,0x4a,0xff,0xfe,0x02,0x2b,0xa4}, 8333},
+ {{0x26,0x00,0x88,0x07,0x50,0x80,0x33,0x01,0x14,0x87,0x83,0xb7,0x33,0xd7,0xeb,0x97}, 8333},
+ {{0x26,0x01,0x01,0x86,0xc1,0x00,0x6b,0xcd,0x16,0xbd,0xce,0xa1,0x23,0x5d,0x1c,0x19}, 8333},
+ {{0x26,0x01,0x01,0x8c,0x42,0x00,0x28,0xd0,0x0e,0x4d,0xe9,0xff,0xfe,0xc5,0x76,0xd0}, 8333},
+ {{0x26,0x01,0x02,0x47,0x82,0x01,0x62,0x51,0x30,0xe6,0x7b,0x95,0x69,0xbf,0x92,0x48}, 8333},
+ {{0x26,0x01,0x06,0x02,0x99,0x80,0x0f,0x78,0x02,0x11,0x11,0xff,0xfe,0xc5,0x01,0xae}, 8333},
+ {{0x26,0x02,0x00,0xae,0x19,0x93,0xde,0x00,0x2c,0x50,0x9a,0x44,0x8f,0x11,0x77,0xa5}, 8333},
+ {{0x26,0x02,0xff,0x68,0x00,0x00,0x00,0x01,0x02,0x1e,0x0b,0xff,0xfe,0xca,0xdb,0x72}, 8333},
+ {{0x26,0x02,0xff,0x68,0x00,0x00,0x00,0x01,0x02,0xbd,0x27,0xff,0xfe,0xb0,0xad,0xf8}, 8333},
+ {{0x26,0x02,0xff,0x68,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}, 8333},
+ {{0x26,0x02,0xff,0x68,0x00,0x00,0x00,0x05,0x02,0xbd,0x27,0xff,0xfe,0xb0,0xad,0xf8}, 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,0x9e,0x63,0x27,0xa2}, 8333},
+ {{0x26,0x02,0xff,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x30,0x1c,0x75}, 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},
+ {{0x26,0x04,0x01,0x80,0x00,0x02,0x0e,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0xca,0x46}, 8333},
+ {{0x26,0x04,0x08,0x80,0x00,0x0d,0x00,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0xbe,0x37}, 8333},
+ {{0x26,0x04,0x9a,0x00,0x21,0x00,0xa0,0x09,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x03,0x01,0x80,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x04,0xa9,0x10,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x05,0x3a,0xc0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0a,0xd7,0xe0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0d,0xcf,0xf0,0x01}, 8333},
+ {{0x26,0x05,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50}, 8333},
+ {{0x26,0x05,0x60,0x00,0xed,0xc8,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xdd,0xfe}, 8333},
+ {{0x26,0x05,0x60,0x00,0xff,0xc0,0x00,0x70,0x74,0xd5,0x22,0x5c,0xf5,0x53,0x5b,0xb8}, 8333},
+ {{0x26,0x06,0x60,0x00,0xc1,0x48,0x70,0x03,0x50,0x54,0x00,0xff,0xfe,0x78,0x66,0xff}, 8333},
+ {{0x26,0x06,0x60,0x00,0xe6,0xd6,0xd7,0x01,0xd4,0x28,0x5e,0x44,0xa2,0xc9,0x3f,0xf6}, 8333},
+ {{0x26,0x06,0xc6,0x80,0x00,0x01,0x00,0x4a,0x20,0x16,0xd1,0xff,0xfe,0x93,0x52,0xa7}, 8333},
+ {{0x26,0x07,0x53,0x00,0x02,0x03,0x01,0x18,0x37,0x33,0x00,0x00,0x00,0x00,0x14,0x14}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x13,0xbb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x19,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x22,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x37,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x3d,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0xa6,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0xa7,0xa3,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,0x60,0xcf,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0xf0,0xd0,0x19,0x01,0x00,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06}, 8333},
+ {{0x26,0x07,0xf1,0x28,0x00,0x40,0x12,0x02,0x00,0x69,0x01,0x62,0x01,0x39,0x01,0x25}, 8333},
+ {{0x26,0x07,0xf1,0x28,0x00,0x40,0x17,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x26,0x07,0xf1,0x78,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06}, 8333},
+ {{0x26,0x07,0xf1,0xc0,0x08,0x4d,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x0c,0xad}, 8333},
+ {{0x26,0x07,0xf9,0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x40}, 8333},
+ {{0x26,0x07,0xfc,0xd0,0x01,0x00,0x23,0x02,0x00,0x00,0x00,0x00,0x60,0x94,0x63,0x5a}, 8333},
+ {{0x26,0x07,0xfc,0xd0,0x01,0x00,0x6a,0x00,0x00,0x00,0x00,0x00,0x3a,0x96,0x00,0x01}, 8333},
+ {{0x26,0x07,0xfc,0xd0,0x01,0x00,0x6a,0x02,0x00,0x00,0x00,0x00,0x7f,0xf0,0x00,0x01}, 8333},
+ {{0x26,0x07,0xfc,0xd0,0x01,0x00,0x82,0x03,0x00,0x00,0x00,0x00,0x8c,0x58,0x0d,0xbc}, 8333},
+ {{0x26,0x07,0xfe,0xa8,0x13,0x60,0x09,0xc2,0x22,0x1a,0x06,0xff,0xfe,0x47,0x77,0x6d}, 8333},
+ {{0x26,0x07,0xfe,0xa8,0x4d,0xa0,0x09,0xce,0x51,0x14,0xa8,0xec,0x20,0xf5,0xa5,0x0b}, 8333},
+ {{0x26,0x07,0xfe,0xa8,0x05,0xdf,0xfd,0xa0,0xfe,0xaa,0x14,0xff,0xfe,0xda,0xc7,0x9a}, 8333},
+ {{0x26,0x07,0xfe,0xa8,0x84,0xc0,0x01,0x63,0xf4,0x2c,0xba,0xff,0xfe,0xcc,0x6b,0xbf}, 8333},
+ {{0x26,0x07,0xff,0x10,0x00,0xc5,0x05,0x02,0x02,0x25,0x90,0xff,0xfe,0x32,0xd4,0x46}, 8333},
+ {{0x26,0x07,0xff,0x48,0xaa,0x81,0x08,0x00,0x00,0x00,0x00,0x00,0x96,0xcf,0x00,0x01}, 8333},
+ {{0x26,0x20,0x01,0x1c,0x50,0x01,0x11,0x18,0xd2,0x67,0xe5,0xff,0xfe,0xe9,0xe6,0x73}, 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},
+ {{0x2a,0x00,0x11,0x78,0x00,0x02,0x00,0x43,0x19,0xfd,0xd4,0x3e,0x0b,0x77,0xed,0xeb}, 8333},
+ {{0x2a,0x00,0x11,0x78,0x00,0x02,0x00,0x43,0xb4,0xe3,0xe5,0x62,0xf8,0x11,0xd7,0x61}, 8333},
{{0x2a,0x00,0x14,0xf0,0xe0,0x00,0x80,0xd2,0xcd,0x1a,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x00,0x16,0x30,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,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,0x16,0x30,0x00,0x02,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}, 8333},
+ {{0x2a,0x00,0x17,0x68,0x20,0x01,0x00,0x24,0x00,0x00,0x00,0x00,0x01,0x48,0x02,0x18}, 8333},
+ {{0x2a,0x00,0x17,0x68,0x20,0x01,0x00,0x27,0x00,0x00,0x00,0x00,0x01,0x42,0x00,0x21}, 8333},
+ {{0x2a,0x00,0x1a,0x48,0x78,0x10,0x01,0x01,0xbe,0x76,0x4e,0xff,0xfe,0x08,0xc7,0x74}, 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,0x1d,0xc0,0x22,0x55,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 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,0x00,0xbb,0xe0,0x00,0x00,0x00,0x42,0x02,0x22,0x64,0xff,0xfe,0x9a,0xe2,0x06}, 8333},
+ {{0x2a,0x00,0x0c,0x98,0x20,0x50,0xa0,0x20,0x00,0x03,0x00,0x00,0x00,0x00,0x01,0x10}, 8333},
+ {{0x2a,0x00,0xdc,0xc0,0x0e,0xda,0x00,0x98,0x01,0x83,0x01,0x93,0x1d,0x24,0xb5,0x3a}, 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,0x00,0x0f,0x90,0x0f,0xf0,0xc1,0x00,0x53,0xc4,0x97,0xa7,0x8b,0x59,0x79,0x6a}, 8333},
+ {{0x2a,0x01,0x02,0x38,0x43,0x5c,0xde,0x00,0xb1,0x10,0x38,0xcf,0x19,0x2d,0x0b,0x2c}, 28333},
+ {{0x2a,0x01,0x03,0x48,0x00,0x06,0x07,0xcf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x03,0x68,0xe0,0x12,0x88,0x88,0x02,0x16,0x3e,0xff,0xfe,0x24,0x11,0x62}, 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,0x05,0x23,0xff,0xa7,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0x88,0x00,0x67,0x10,0x00,0xb0,0x1c,0x33,0x79,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},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x02,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x03,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x05,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x06,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x08,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x08,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x0d,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x10,0x33,0x4c,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,0x21,0x43,0x46,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,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,0x31,0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x40,0x88,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,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,0x13,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xc4,0x51}, 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,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,0x41,0x22,0xae,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x41,0x32,0x2c,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,0x44,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x61,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x72,0x6b,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}, 15000},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x41,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x41,0xcc,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,0x51,0x60,0x0b,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01}, 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,0x53,0x28,0x00,0x00,0x00,0x00,0x27,0xf0,0x18,0x7a}, 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,0x61,0x21,0xad,0x00,0x00,0x00,0x00,0x03,0x33,0x00,0x30}, 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,0x62,0x41,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x43,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,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,0x2a,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x2e,0x1b,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,0x32,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x38,0x0c,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,0x71,0x0d,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x11,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x12,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x17,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x1c,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x21,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x3a,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x3b,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x3e,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x3e,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x0a,0xeb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x0a,0xec,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x73,0x10,0xab,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x73,0x15,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x73,0x1b,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x73,0x1e,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x73,0x21,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x73,0x21,0xe6,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,0x73,0x0c,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x12,0x53,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,0x34,0xf0,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,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,0x91,0x81,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 22556},
+ {{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,0x11,0xb2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8343},
{{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,0x22,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x24,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x34,0xd0,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,0x52,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x2a,0x01,0x04,0xf8,0x01,0x92,0x00,0xdb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x2a,0x01,0x04,0xf8,0x02,0x00,0x10,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x00,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,0x01,0x03,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x41,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x41,0x6a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x21,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x40,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11}, 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,0x12,0xd6,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,0x32,0xc6,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,0x04,0xf8,0x02,0x11,0x1e,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x04,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x0d,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x12,0x18,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x12,0x27,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x21,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x12,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x74,0x6a,0x01,0x01,0x00,0x01,0x00,0x01,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x82,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x2e,0xef,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x2f,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 3333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x3b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x42,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x46,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x4a,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x4c,0x5d,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,0x6d,0xd0,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,0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x72,0xc6,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,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,0x9c,0xce,0xbc,0x85,0x7c,0x98,0xc1,0x88,0xff,0xfe,0xf5,0x90,0xde}, 8333},
+ {{0x2a,0x01,0x07,0x9d,0x73,0x77,0x26,0x29,0x7e,0x57,0x7e,0x57,0x00,0x01,0x00,0x01}, 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,0x07,0xc8,0xaa,0xb5,0x03,0xe6,0x50,0x54,0x00,0xff,0xfe,0xd7,0x4e,0x54}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xbd,0x03,0xd5,0x50,0x54,0x00,0xff,0xfe,0x95,0xf5,0x86}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xc1,0x04,0x53,0xd0,0xd2,0xaf,0x96,0xfa,0x88,0x5d,0x0e}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xc3,0x06,0x63,0x50,0x54,0x00,0xff,0xfe,0x25,0x8c,0x69}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xc3,0x00,0x97,0x50,0x54,0x00,0xff,0xfe,0xa7,0x37,0x80}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xc4,0x05,0x67,0x50,0x54,0x00,0xff,0xfe,0xdc,0x51,0x8a}, 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,0x50,0x94,0xb8}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x55,0x00,0x2c}, 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,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x89,0x53,0xfd}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xdf,0xb7,0x0f}, 8333},
+ {{0x2a,0x01,0xb0,0x00,0x00,0x00,0x00,0x00,0x41,0x66,0x51,0x5b,0xef,0x9e,0x00,0xb3}, 8333},
+ {{0x2a,0x01,0xb2,0xe0,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40}, 8333},
+ {{0x2a,0x01,0x0e,0x34,0xec,0x29,0x24,0xc0,0x00,0xf3,0xdd,0xaf,0x9f,0x59,0x58,0x6f}, 8333},
+ {{0x2a,0x01,0x0e,0x34,0xee,0xd7,0x66,0x70,0xec,0x1b,0xbf,0x7c,0xb0,0x12,0x60,0x69}, 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,0x27,0xf8,0x20,0x12,0x00,0x00,0xe9,0xf7,0x26,0x8f,0xc4,0x41,0x61,0x29}, 8333},
+ {{0x2a,0x01,0x0e,0x35,0x8b,0xff,0x70,0xb0,0x1e,0x1b,0x0d,0xff,0xfe,0x0b,0x23,0x6d}, 8333},
+ {{0x2a,0x02,0x12,0x05,0x34,0xc3,0xa4,0xe0,0xd6,0x3d,0x7e,0xff,0xfe,0x98,0x10,0xc8}, 8333},
+ {{0x2a,0x02,0x12,0x05,0x34,0xda,0xaa,0x00,0x58,0x82,0x24,0x9d,0xdd,0xbf,0xbc,0x43}, 8333},
+ {{0x2a,0x02,0x12,0x05,0x50,0x51,0xa6,0x40,0xd6,0xae,0x52,0xff,0xfe,0xa3,0x00,0xac}, 8333},
+ {{0x2a,0x02,0x12,0x05,0xc6,0x89,0xd9,0x80,0xba,0xae,0xed,0xff,0xfe,0xea,0x94,0x45}, 8333},
+ {{0x2a,0x02,0x12,0x0b,0x2c,0x2a,0x5e,0xc0,0x10,0xdd,0x31,0xff,0xfe,0x42,0x50,0x79}, 8333},
+ {{0x2a,0x02,0x12,0x0b,0x2c,0x35,0x69,0xd0,0x02,0x19,0x99,0xff,0xfe,0x6b,0x4e,0xc3}, 8333},
+ {{0x2a,0x02,0x12,0x0b,0xc3,0xc2,0xff,0x60,0x02,0x1f,0x5b,0xff,0xfe,0xc3,0xa7,0xad}, 24312},
+ {{0x2a,0x02,0x13,0xb8,0x40,0x00,0x10,0x00,0x02,0x16,0xe6,0xff,0xfe,0x92,0x86,0x19}, 8333},
+ {{0x2a,0x02,0x13,0xb8,0x40,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27}, 8333},
+ {{0x2a,0x02,0x17,0xd0,0x00,0x2a,0x44,0x00,0x04,0x0f,0x3d,0xd4,0xb0,0x53,0x47,0xad}, 8333},
+ {{0x2a,0x02,0x01,0x80,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x05,0x17,0x0a,0xfb}, 8333},
+ {{0x2a,0x02,0x01,0x80,0x00,0x06,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18}, 8333},
+ {{0x2a,0x02,0x18,0x10,0x1d,0x11,0xf9,0x00,0x68,0x72,0xf2,0x8e,0x81,0x26,0xf6,0x35}, 8333},
+ {{0x2a,0x02,0x27,0xa8,0x00,0x00,0x00,0x01,0x52,0xe5,0x49,0xff,0xfe,0xe3,0x3b,0x49}, 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,0x03,0x90,0x90,0x00,0x00,0x00,0x02,0x18,0x7d,0xff,0xfe,0x10,0xbe,0x33}, 8333},
+ {{0x2a,0x02,0x05,0x82,0x78,0xc1,0x76,0x00,0x2d,0x49,0x62,0x12,0x29,0xd3,0x0a,0xbb}, 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,0x07,0x50,0x00,0x07,0x33,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x75}, 8333},
+ {{0x2a,0x02,0x07,0x52,0x01,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53}, 8333},
+ {{0x2a,0x02,0x7a,0xa0,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x75,0x01,0xd9,0x50}, 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,0x7a,0xa0,0x16,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x37,0x69,0xa6}, 8333},
+ {{0x2a,0x02,0x81,0x0d,0x14,0xc0,0x86,0x94,0xd2,0x50,0x99,0xff,0xfe,0x81,0x23,0xd9}, 8333},
+ {{0x2a,0x02,0x0a,0x50,0x00,0x00,0x00,0x00,0xda,0xcb,0x8a,0xff,0xfe,0x36,0x8d,0x2d}, 8333},
+ {{0x2a,0x02,0xc2,0x00,0x00,0x00,0x00,0x10,0x00,0x03,0x00,0x00,0x25,0x91,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x00,0x00,0x01,0x00,0x10,0x00,0x02,0x00,0x05,0x99,0x82,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x00,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x00,0x92,0x90,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x05,0x30,0x00,0x71,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x05,0x30,0x01,0x45,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x05,0x30,0x01,0x65,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x08,0x37,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x08,0x65,0x19,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,0x09,0x78,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x10,0x03,0x02,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,0xce,0x80,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
{{0x2a,0x03,0x40,0x00,0x00,0x02,0x04,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}, 8333},
+ {{0x2a,0x03,0x40,0x00,0x00,0x06,0x41,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53}, 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,0x40,0x00,0x00,0x09,0x00,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x03,0x73,0x80,0x21,0x40,0x00,0x17,0x51,0xfe,0x35,0x19,0xb5,0x71,0x4a,0x13}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x00,0x07,0xa3,0x10,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x00,0x07,0xaa,0x40,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,0x22,0x08,0x60,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,0x90,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,0x70,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,0xe0,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,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,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,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,0xf0,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,0xb0,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},
+ {{0x2a,0x04,0x19,0x80,0x31,0x00,0x1a,0xac,0xe6,0x1d,0x2d,0xff,0xfe,0x29,0xf2,0x41}, 8333},
+ {{0x2a,0x04,0x19,0x80,0x31,0x00,0x1a,0xac,0xe6,0x1d,0x2d,0xff,0xfe,0x29,0xf2,0x51}, 8333},
+ {{0x2a,0x04,0x21,0x80,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x5a,0x49,0x3c,0x06}, 8333},
+ {{0x2a,0x04,0x21,0x80,0x00,0x01,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x2a,0x04,0x2e,0x00,0x00,0x05,0x00,0x2e,0x9a,0x4b,0xe1,0xff,0xfe,0x62,0x6d,0xc0}, 8333},
+ {{0x2a,0x04,0x35,0x42,0x10,0x00,0x09,0x10,0x84,0x92,0xb8,0xff,0xfe,0x91,0x71,0x1d}, 8333},
+ {{0x2a,0x04,0xdb,0xc3,0xff,0xfe,0x00,0x00,0xe6,0x1f,0x13,0xff,0xfe,0x95,0x84,0x01}, 8333},
+ {{0x2a,0x06,0x9f,0xc0,0x2a,0x06,0x9f,0xc0,0x2a,0x06,0x9f,0xc1,0x06,0x7c,0xe7,0x06}, 8333},
+ {{0x2c,0x0f,0xf7,0x38,0x20,0x04,0x00,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd1,0xe3,0x80,0xee,0x87,0xdc,0xf3,0x63,0x37,0x00}, 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},
- {{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,0xdc,0x09,0x14,0x6e,0x6c,0x3e,0x58,0xf2,0x1b,0x15}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe5,0x86,0xa6,0xb0,0x82,0x31,0xc4,0xc1,0x2e,0x1d}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xee,0xe7,0x24,0xcf,0xd9,0x86,0xd0,0x09,0x57,0xb0}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe8,0x8d,0xf8,0x13,0x16,0xad,0x9d,0xea,0xdd,0xf3}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe9,0x82,0x28,0x9a,0x17,0x10,0x6e,0x9d,0x77,0x72}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf0,0x9b,0xc4,0x2c,0x36,0x54,0x54,0x7f,0x9a,0xce}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf1,0x38,0x98,0xb5,0xbf,0x41,0x89,0x0b,0xb1,0x65}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf6,0x18,0x60,0xd5,0xad,0xf0,0xfa,0xd2,0xb2,0xbc}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf6,0x64,0x7d,0x84,0xa3,0xa1,0xde,0xef,0xac,0x6b}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xfe,0x8b,0x0f,0x3c,0xf5,0xe1,0x4d,0xc8,0x9e,0xa7}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf9,0x87,0x07,0xf9,0xaf,0xa4,0x95,0xc5,0x96,0xca}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x07,0xc8,0xcb,0xb9,0x7d,0xe9,0x3d,0xad,0xae,0x02}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x04,0xa4,0x14,0x60,0x79,0x44,0x3f,0xfc,0x81,0x48}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x08,0x0a,0xae,0xa1,0xc0,0x9a,0xcd,0x3f,0x8c,0xcb}, 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,0x0c,0x6d,0x02,0x65,0xbe,0x59,0x3b,0xcb,0x68,0x21}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0c,0xb8,0x18,0x7a,0x5e,0x82,0xab,0x3e,0x9d,0xe8}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0d,0x1f,0xd6,0xf4,0x9b,0x55,0x23,0x54,0xe4,0xbb}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x16,0xa6,0xf8,0x28,0x19,0xe2,0x0e,0x9c,0xd8,0xc1}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x11,0x22,0xd8,0xb2,0x2a,0xee,0x5c,0xcc,0xbb,0x2d}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x11,0x70,0x43,0x27,0xdc,0x3c,0xf6,0x97,0xb8,0x71}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x11,0xbb,0x53,0x77,0x82,0x06,0x72,0xfa,0xba,0x86}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x11,0x95,0xca,0x69,0x77,0x8d,0x58,0xbe,0x26,0xa1}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x12,0x70,0x61,0xfd,0xf4,0xea,0xe0,0xa5,0x63,0xa9}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1f,0xad,0x40,0xc8,0x73,0x8f,0x3c,0x31,0xf5,0x48}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x19,0x61,0xec,0x24,0x5b,0x01,0x16,0xf5,0xda,0x3c}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1c,0x1f,0x7b,0x2d,0xed,0xae,0xf3,0xb3,0xe5,0xab}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x20,0x18,0x57,0x49,0xf4,0xa9,0x00,0x10,0x21,0x83}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x23,0xf4,0xc4,0xe5,0xd7,0xda,0xaa,0x1f,0x02,0xfc}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2b,0xc3,0x70,0xf2,0xc9,0xa0,0xd1,0x6d,0x5b,0xa0}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2d,0x3a,0x72,0xc8,0x21,0x2f,0x53,0x69,0x54,0xf5}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x37,0x0b,0x12,0x39,0x01,0x90,0xb3,0x44,0xac,0x9b}, 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,0x31,0x87,0x8d,0x3c,0x3a,0x05,0x56,0x19,0xa6,0xd0}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x31,0xf4,0x04,0x0c,0x79,0xbb,0x2b,0x88,0xb6,0x84}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x33,0x6e,0x6c,0x2c,0x26,0xcd,0x40,0x0c,0xaa,0x1f}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3b,0x51,0x91,0xdd,0xa4,0x49,0x17,0xee,0x50,0x2a}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3c,0xea,0x31,0x31,0x62,0xd8,0x02,0x94,0x68,0x01}, 8443},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3d,0xa8,0x17,0x39,0x12,0xe1,0xa4,0xba,0x3c,0xd7}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3d,0xf3,0xe3,0x3a,0xcb,0xa0,0xd6,0x9f,0x0f,0xa0}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4f,0xa8,0xc7,0x70,0x2d,0x96,0x66,0xf9,0x39,0xa2}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x48,0xe8,0xd6,0x01,0xc2,0xb0,0x42,0xdb,0x77,0xdd}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x54,0xeb,0xb8,0x2e,0xeb,0xfd,0xea,0xc1,0xac,0xbc}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x55,0x47,0xce,0x4a,0xdf,0x92,0x83,0xd2,0xb9,0x76}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x55,0x90,0xc6,0xe5,0x9e,0xa8,0xf9,0x90,0x2a,0xab}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x58,0x3b,0x73,0xab,0x6b,0x7c,0x6f,0x9b,0xb3,0x3a}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x58,0xbe,0x2b,0xfb,0xe4,0x68,0xf5,0xea,0x52,0x6f}, 8352},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x65,0xa9,0xd7,0x1b,0x40,0x30,0xa4,0xf6,0x19,0x57}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x66,0x6e,0xa4,0x3d,0x18,0x22,0x80,0xe3,0xfd,0x98}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6f,0xa3,0x65,0xc6,0x76,0x7c,0x05,0xf8,0x59,0xdf}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0x77,0xee,0x6b,0x98,0x10,0xa0,0xf3,0xfb,0x59}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x76,0xbb,0xeb,0x7e,0x7b,0xa8,0x8c,0xa9,0xb2,0xea}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x77,0x24,0xbe,0xb4,0x1e,0x49,0x20,0x64,0x6d,0x7e}, 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,0x76,0x08,0x1c,0x0d,0x7a,0x78,0x05,0x7f,0x57,0x5e}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7f,0x59,0x7d,0x21,0x89,0xff,0x46,0xf6,0x21,0x84}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7c,0x84,0xef,0x06,0xe9,0x25,0x96,0x98,0x8b,0x37}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7d,0xe6,0x69,0x58,0x93,0xf4,0xd6,0x68,0x86,0xc9}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x88,0x79,0x5d,0x94,0xe6,0xbe,0xb3,0x1e,0x46,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,0xc0,0x54,0x31,0x42,0x9d,0x73,0xed,0xad,0x66}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8d,0xd3,0x5c,0x74,0x98,0x9c,0xc8,0xfe,0xce,0x72}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x91,0x1d,0x25,0x50,0x79,0x57,0xaa,0xdf,0x32,0x19}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9b,0xcc,0x3a,0x16,0xf7,0x95,0xb6,0x95,0x44,0x65}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9d,0x11,0x8a,0xc0,0xc8,0xdb,0xbd,0xfe,0xbd,0x21}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9d,0xf9,0x91,0xfc,0x7d,0x25,0xdc,0xd6,0x85,0x67}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa3,0x94,0x6f,0x02,0xa5,0x30,0x4e,0xe2,0xae,0x5b}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xae,0xcc,0x97,0x9c,0xd0,0xc7,0x4f,0x83,0x09,0x8b}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa9,0xc6,0xeb,0xc2,0x1e,0xdd,0xe3,0xdd,0xb9,0x7f}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xaa,0x24,0x4a,0xc5,0x19,0xce,0xe1,0x4c,0x00,0xc9}, 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,0xb1,0x65,0x7d,0x19,0x1f,0x1a,0x4f,0x8d,0x68,0xea}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb1,0xbd,0x5b,0x30,0x31,0xce,0x31,0x90,0x3e,0x8d}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbd,0x03,0xcb,0x6e,0xdc,0xb5,0x95,0xdf,0x5d,0x10}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc0,0x91,0x56,0xb9,0x9c,0xe0,0xd9,0x7b,0xf1,0xc1}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc5,0xa4,0xaa,0x14,0x5e,0xd0,0x4b,0xa2,0xd1,0x9c}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcf,0x0a,0x0b,0xea,0xb7,0x36,0xb7,0x3d,0x0c,0x65}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcb,0xba,0x35,0x2e,0xc4,0x5b,0x07,0x17,0xbb,0xad}, 8333}
};
static SeedSpec6 pnSeed6_test[] = {
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index aefddce464..13b5876530 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -6,7 +6,7 @@
#include "chain.h"
#include "chainparams.h"
-#include "main.h"
+#include "validation.h"
#include "uint256.h"
#include <stdint.h>
@@ -15,56 +15,6 @@
namespace Checkpoints {
- /**
- * How many times slower we expect checking transactions after the last
- * checkpoint to be (from checking signatures, which is skipped up to the
- * last checkpoint). This number is a compromise, as it can't be accurate
- * for every system. When reindexing from a fast disk with a slow CPU, it
- * can be up to 20, while when downloading from a slow network with a
- * fast multicore CPU, it won't be much higher than 1.
- */
- static const double SIGCHECK_VERIFICATION_FACTOR = 5.0;
-
- //! Guess how far we are in the verification process at the given block index
- double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) {
- if (pindex==NULL)
- return 0.0;
-
- int64_t nNow = time(NULL);
-
- double fSigcheckVerificationFactor = fSigchecks ? SIGCHECK_VERIFICATION_FACTOR : 1.0;
- double fWorkBefore = 0.0; // Amount of work done before pindex
- double fWorkAfter = 0.0; // Amount of work left after pindex (estimated)
- // Work is defined as: 1.0 per transaction before the last checkpoint, and
- // fSigcheckVerificationFactor per transaction after.
-
- if (pindex->nChainTx <= data.nTransactionsLastCheckpoint) {
- double nCheapBefore = pindex->nChainTx;
- double nCheapAfter = data.nTransactionsLastCheckpoint - pindex->nChainTx;
- double nExpensiveAfter = (nNow - data.nTimeLastCheckpoint)/86400.0*data.fTransactionsPerDay;
- fWorkBefore = nCheapBefore;
- fWorkAfter = nCheapAfter + nExpensiveAfter*fSigcheckVerificationFactor;
- } else {
- double nCheapBefore = data.nTransactionsLastCheckpoint;
- double nExpensiveBefore = pindex->nChainTx - data.nTransactionsLastCheckpoint;
- double nExpensiveAfter = (nNow - pindex->GetBlockTime())/86400.0*data.fTransactionsPerDay;
- fWorkBefore = nCheapBefore + nExpensiveBefore*fSigcheckVerificationFactor;
- fWorkAfter = nExpensiveAfter*fSigcheckVerificationFactor;
- }
-
- return fWorkBefore / (fWorkBefore + fWorkAfter);
- }
-
- int GetTotalBlocksEstimate(const CCheckpointData& data)
- {
- const MapCheckpoints& checkpoints = data.mapCheckpoints;
-
- if (checkpoints.empty())
- return 0;
-
- return checkpoints.rbegin()->first;
- }
-
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data)
{
const MapCheckpoints& checkpoints = data.mapCheckpoints;
diff --git a/src/checkpoints.h b/src/checkpoints.h
index cd25ea5379..7449d1063b 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -19,14 +19,9 @@ struct CCheckpointData;
namespace Checkpoints
{
-//! Return conservative estimate of total number of blocks, 0 if unknown
-int GetTotalBlocksEstimate(const CCheckpointData& data);
-
//! Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data);
-double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex* pindex, bool fSigchecks = true);
-
} //namespace Checkpoints
#endif // BITCOIN_CHECKPOINTS_H
diff --git a/src/checkqueue.h b/src/checkqueue.h
index 32e25d5c8c..63c104c02a 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_CHECKQUEUE_H
#define BITCOIN_CHECKQUEUE_H
+#include "sync.h"
+
#include <algorithm>
#include <vector>
@@ -127,6 +129,9 @@ 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) {}
@@ -161,12 +166,6 @@ public:
{
}
- bool IsIdle()
- {
- boost::unique_lock<boost::mutex> lock(mutex);
- return (nTotal == nIdle && nTodo == 0 && fAllOk == true);
- }
-
};
/**
@@ -177,16 +176,18 @@ 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);
+ ENTER_CRITICAL_SECTION(pqueue->ControlMutex);
}
}
@@ -209,6 +210,9 @@ public:
{
if (!fDone)
Wait();
+ if (pqueue != NULL) {
+ LEAVE_CRITICAL_SECTION(pqueue->ControlMutex);
+ }
}
};
diff --git a/src/clientversion.cpp b/src/clientversion.cpp
index bfe9e16f80..d2344ded09 100644
--- a/src/clientversion.cpp
+++ b/src/clientversion.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2014 The Bitcoin Core developers
+// Copyright (c) 2012-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.
diff --git a/src/clientversion.h b/src/clientversion.h
index 47263d5344..3d5392619b 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -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 12
-#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 39db7dedfb..b2e33abf33 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -117,17 +117,37 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
return CCoinsModifier(*this, ret.first, cachedCoinUsage);
}
-// ModifyNewCoins has to know whether the new outputs its creating are for a
-// coinbase or not. If they are for a coinbase, it can not mark them as fresh.
-// This is to ensure that the historical duplicate coinbases before BIP30 was
-// in effect will still be properly overwritten when spent.
+/* 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()));
- ret.first->second.coins.Clear();
if (!coinbase) {
- ret.first->second.flags = CCoinsCacheEntry::FRESH;
+ // 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!");
+
+ 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;
+ }
}
+ ret.first->second.coins.Clear();
ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
return CCoinsModifier(*this, ret.first, 0);
}
@@ -187,6 +207,13 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
entry.flags |= CCoinsCacheEntry::FRESH;
}
} else {
+ // Assert that the child cache entry was not marked FRESH if the
+ // 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())
+ 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()) {
// The grandparent does not have an entry, and the child is
@@ -200,6 +227,11 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
itUs->second.coins.swap(it->second.coins);
cachedCoinsUsage += itUs->second.coins.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
+ // we must not copy that FRESH flag to the parent as that
+ // pruned state likely still needs to be communicated to the
+ // grandparent.
}
}
}
@@ -263,25 +295,6 @@ 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 += 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;
diff --git a/src/coins.h b/src/coins.h
index 033651a435..065bae56e9 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -1,11 +1,12 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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_COINS_H
#define BITCOIN_COINS_H
+#include "primitives/transaction.h"
#include "compressor.h"
#include "core_memusage.h"
#include "hash.h"
@@ -17,7 +18,7 @@
#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
@@ -153,31 +154,8 @@ public:
return fCoinBase;
}
- unsigned int GetSerializeSize(int nType, int nVersion) const {
- unsigned int nSize = 0;
- 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
- nSize += ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion);
- // size of header code
- nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
- // spentness bitmask
- nSize += nMaskSize;
- // txouts themself
- for (unsigned int i = 0; i < vout.size(); i++)
- if (!vout[i].IsNull())
- nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion);
- // height
- nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
- return nSize;
- }
-
template<typename Stream>
- void Serialize(Stream &s, int nType, int nVersion) const {
+ void Serialize(Stream &s) const {
unsigned int nMaskSize = 0, nMaskCode = 0;
CalcMaskSize(nMaskSize, nMaskCode);
bool fFirst = vout.size() > 0 && !vout[0].IsNull();
@@ -185,33 +163,33 @@ public:
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), nType, nVersion);
+ ::Serialize(s, VARINT(this->nVersion));
// header code
- ::Serialize(s, VARINT(nCode), nType, nVersion);
+ ::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, nType, nVersion);
+ ::Serialize(s, chAvail);
}
// txouts themself
for (unsigned int i = 0; i < vout.size(); i++) {
if (!vout[i].IsNull())
- ::Serialize(s, CTxOutCompressor(REF(vout[i])), nType, nVersion);
+ ::Serialize(s, CTxOutCompressor(REF(vout[i])));
}
// coinbase height
- ::Serialize(s, VARINT(nHeight), nType, nVersion);
+ ::Serialize(s, VARINT(nHeight));
}
template<typename Stream>
- void Unserialize(Stream &s, int nType, int nVersion) {
+ void Unserialize(Stream &s) {
unsigned int nCode = 0;
// version
- ::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
+ ::Unserialize(s, VARINT(this->nVersion));
// header code
- ::Unserialize(s, VARINT(nCode), nType, nVersion);
+ ::Unserialize(s, VARINT(nCode));
fCoinBase = nCode & 1;
std::vector<bool> vAvail(2, false);
vAvail[0] = (nCode & 2) != 0;
@@ -220,7 +198,7 @@ public:
// spentness bitmask
while (nMaskCode > 0) {
unsigned char chAvail = 0;
- ::Unserialize(s, chAvail, nType, nVersion);
+ ::Unserialize(s, chAvail);
for (unsigned int p = 0; p < 8; p++) {
bool f = (chAvail & (1 << p)) != 0;
vAvail.push_back(f);
@@ -232,10 +210,10 @@ public:
vout.assign(vAvail.size(), CTxOut());
for (unsigned int i = 0; i < vAvail.size(); i++) {
if (vAvail[i])
- ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion);
+ ::Unserialize(s, REF(CTxOutCompressor(vout[i])));
}
// coinbase height
- ::Unserialize(s, VARINT(nHeight), nType, nVersion);
+ ::Unserialize(s, VARINT(nHeight));
Cleanup();
}
@@ -292,12 +270,17 @@ struct CCoinsCacheEntry
enum Flags {
DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
FRESH = (1 << 1), // The parent view does not have this entry (or it is pruned).
+ /* Note that FRESH is a performance optimization with which we can
+ * erase coins that are fully spent if we know we do not need to
+ * flush the changes to the parent cache. It is always safe to
+ * not mark FRESH if that condition is not guaranteed.
+ */
};
CCoinsCacheEntry() : coins(), flags(0) {}
};
-typedef boost::unordered_map<uint256, CCoinsCacheEntry, SaltedTxidHasher> CCoinsMap;
+typedef std::unordered_map<uint256, CCoinsCacheEntry, SaltedTxidHasher> CCoinsMap;
/** Cursor for iterating over CoinsView state */
class CCoinsViewCursor
@@ -308,7 +291,6 @@ public:
virtual bool GetKey(uint256 &key) const = 0;
virtual bool GetValue(CCoins &coins) const = 0;
- /* Don't care about GetKeySize here */
virtual unsigned int GetValueSize() const = 0;
virtual bool Valid() const = 0;
@@ -478,19 +460,11 @@ 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::iterator FetchCoins(const uint256 &txid);
CCoinsMap::const_iterator FetchCoins(const uint256 &txid) const;
/**
diff --git a/src/compat.h b/src/compat.h
index 79a297e5e4..e76ab94c82 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -34,6 +34,7 @@
#else
#include <sys/fcntl.h>
#include <sys/mman.h>
+#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <net/if.h>
@@ -46,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
@@ -73,11 +72,6 @@ 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
diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h
index 899220bdc5..3c5a5c0837 100644
--- a/src/compat/byteswap.h
+++ b/src/compat/byteswap.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Bitcoin developers
+// Copyright (c) 2014-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.
@@ -15,6 +15,23 @@
#include <byteswap.h>
#endif
+#if defined(__APPLE__)
+
+#if !defined(bswap_16)
+
+// Mac OS X / Darwin features; we include a check for bswap_16 because if it is already defined, protobuf has
+// defined these macros for us already; if it isn't, we do it ourselves. In either case, we get the exact same
+// result regardless which path was taken
+#include <libkern/OSByteOrder.h>
+#define bswap_16(x) OSSwapInt16(x)
+#define bswap_32(x) OSSwapInt32(x)
+#define bswap_64(x) OSSwapInt64(x)
+
+#endif // !defined(bswap_16)
+
+#else
+// Non-Mac OS X / non-Darwin
+
#if HAVE_DECL_BSWAP_16 == 0
inline uint16_t bswap_16(uint16_t x)
{
@@ -44,4 +61,6 @@ inline uint64_t bswap_64(uint64_t x)
}
#endif // HAVE_DECL_BSWAP64
+#endif // defined(__APPLE__)
+
#endif // BITCOIN_COMPAT_BYTESWAP_H
diff --git a/src/compat/endian.h b/src/compat/endian.h
index 6bfae42c77..79d6b2fdbb 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2015 The Bitcoin developers
+// Copyright (c) 2014-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.
diff --git a/src/compressor.h b/src/compressor.h
index fa702f0dfa..015911484a 100644
--- a/src/compressor.h
+++ b/src/compressor.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// 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.
@@ -55,16 +55,8 @@ protected:
public:
CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
- unsigned int GetSerializeSize(int nType, int nVersion) const {
- std::vector<unsigned char> compr;
- if (Compress(compr))
- return compr.size();
- unsigned int nSize = script.size() + nSpecialScripts;
- return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion);
- }
-
template<typename Stream>
- void Serialize(Stream &s, int nType, int nVersion) const {
+ void Serialize(Stream &s) const {
std::vector<unsigned char> compr;
if (Compress(compr)) {
s << CFlatData(compr);
@@ -76,7 +68,7 @@ public:
}
template<typename Stream>
- void Unserialize(Stream &s, int nType, int nVersion) {
+ void Unserialize(Stream &s) {
unsigned int nSize = 0;
s >> VARINT(nSize);
if (nSize < nSpecialScripts) {
@@ -112,7 +104,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
if (!ser_action.ForRead()) {
uint64_t nVal = CompressAmount(txout.nValue);
READWRITE(VARINT(nVal));
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index 81f40593b2..351911a3a4 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -10,8 +10,8 @@
/** 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 cost for a block, see BIP 141 (network rule) */
-static const unsigned int MAX_BLOCK_COST = 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) */
diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp
index 35f7d2e05a..1ce5a9d87e 100644
--- a/src/consensus/merkle.cpp
+++ b/src/consensus/merkle.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -160,7 +160,7 @@ uint256 BlockMerkleRoot(const CBlock& block, bool* mutated)
std::vector<uint256> leaves;
leaves.resize(block.vtx.size());
for (size_t s = 0; s < block.vtx.size(); s++) {
- leaves[s] = block.vtx[s].GetHash();
+ leaves[s] = block.vtx[s]->GetHash();
}
return ComputeMerkleRoot(leaves, mutated);
}
@@ -171,7 +171,7 @@ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated)
leaves.resize(block.vtx.size());
leaves[0].SetNull(); // The witness hash of the coinbase is 0.
for (size_t s = 1; s < block.vtx.size(); s++) {
- leaves[s] = block.vtx[s].GetWitnessHash();
+ leaves[s] = block.vtx[s]->GetWitnessHash();
}
return ComputeMerkleRoot(leaves, mutated);
}
@@ -181,7 +181,7 @@ std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position)
std::vector<uint256> leaves;
leaves.resize(block.vtx.size());
for (size_t s = 0; s < block.vtx.size(); s++) {
- leaves[s] = block.vtx[s].GetHash();
+ leaves[s] = block.vtx[s]->GetHash();
}
return ComputeMerkleBranch(leaves, position);
}
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 822ec87d69..6240e82857 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -16,7 +16,7 @@ enum DeploymentPos
{
DEPLOYMENT_TESTDUMMY,
DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113.
- DEPLOYMENT_SEGWIT, // Deployment of BIP141 and BIP143
+ DEPLOYMENT_SEGWIT, // Deployment of BIP141, BIP143, and BIP147.
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
@@ -39,15 +39,15 @@ struct BIP9Deployment {
struct Params {
uint256 hashGenesisBlock;
int nSubsidyHalvingInterval;
- /** Used to check majorities for block version upgrade */
- int nMajorityEnforceBlockUpgrade;
- int nMajorityRejectBlockOutdated;
- int nMajorityWindow;
/** Block height and hash at which BIP34 becomes active */
int BIP34Height;
uint256 BIP34Hash;
+ /** Block height at which BIP65 becomes active */
+ int BIP65Height;
+ /** 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.
*/
@@ -61,6 +61,8 @@ struct Params {
int64_t nPowTargetSpacing;
int64_t nPowTargetTimespan;
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
+ uint256 nMinimumChainWork;
+ uint256 defaultAssumeValid;
};
} // namespace Consensus
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 000b197270..5a7d7f11a9 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -22,9 +22,9 @@ static const unsigned char REJECT_CHECKPOINT = 0x43;
class CValidationState {
private:
enum mode_state {
- MODE_VALID, //! everything ok
- MODE_INVALID, //! network rule violation (DoS value may be set)
- MODE_ERROR, //! run-time error
+ MODE_VALID, //!< everything ok
+ MODE_INVALID, //!< network rule violation (DoS value may be set)
+ MODE_ERROR, //!< run-time error
} mode;
int nDoS;
std::string strRejectReason;
diff --git a/src/core_io.h b/src/core_io.h
index b559d44bf5..2d63be5fc4 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -11,22 +11,23 @@
class CBlock;
class CScript;
class CTransaction;
+struct CMutableTransaction;
class uint256;
class UniValue;
// core_read.cpp
-extern CScript ParseScript(const std::string& s);
-extern std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
-extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false);
-extern bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
-extern uint256 ParseHashUV(const UniValue& v, const std::string& strName);
-extern uint256 ParseHashStr(const std::string&, const std::string& strName);
-extern std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
+CScript ParseScript(const std::string& s);
+std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
+bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false);
+bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
+uint256 ParseHashUV(const UniValue& v, const std::string& strName);
+uint256 ParseHashStr(const std::string&, const std::string& strName);
+std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
// core_write.cpp
-extern std::string FormatScript(const CScript& script);
-extern std::string EncodeHexTx(const CTransaction& tx);
-extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
-extern void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry);
+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);
#endif // BITCOIN_CORE_IO_H
diff --git a/src/core_memusage.h b/src/core_memusage.h
index b8e0f08bbf..5e10182075 100644
--- a/src/core_memusage.h
+++ b/src/core_memusage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -18,35 +18,19 @@ static inline size_t RecursiveDynamicUsage(const COutPoint& out) {
}
static inline size_t RecursiveDynamicUsage(const CTxIn& in) {
- return RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.prevout);
-}
-
-static inline size_t RecursiveDynamicUsage(const CTxOut& out) {
- return RecursiveDynamicUsage(out.scriptPubKey);
-}
-
-static inline size_t RecursiveDynamicUsage(const CScriptWitness& scriptWit) {
- size_t mem = memusage::DynamicUsage(scriptWit.stack);
- for (std::vector<std::vector<unsigned char> >::const_iterator it = scriptWit.stack.begin(); it != scriptWit.stack.end(); it++) {
- mem += memusage::DynamicUsage(*it);
+ size_t mem = RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.prevout) + memusage::DynamicUsage(in.scriptWitness.stack);
+ for (std::vector<std::vector<unsigned char> >::const_iterator it = in.scriptWitness.stack.begin(); it != in.scriptWitness.stack.end(); it++) {
+ mem += memusage::DynamicUsage(*it);
}
return mem;
}
-static inline size_t RecursiveDynamicUsage(const CTxInWitness& txinwit) {
- return RecursiveDynamicUsage(txinwit.scriptWitness);
-}
-
-static inline size_t RecursiveDynamicUsage(const CTxWitness& txwit) {
- size_t mem = memusage::DynamicUsage(txwit.vtxinwit);
- for (std::vector<CTxInWitness>::const_iterator it = txwit.vtxinwit.begin(); it != txwit.vtxinwit.end(); it++) {
- mem += RecursiveDynamicUsage(*it);
- }
- return mem;
+static inline size_t RecursiveDynamicUsage(const CTxOut& out) {
+ return RecursiveDynamicUsage(out.scriptPubKey);
}
static inline size_t RecursiveDynamicUsage(const CTransaction& tx) {
- size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout) + RecursiveDynamicUsage(tx.wit);
+ size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
mem += RecursiveDynamicUsage(*it);
}
@@ -57,7 +41,7 @@ static inline size_t RecursiveDynamicUsage(const CTransaction& tx) {
}
static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) {
- size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout) + RecursiveDynamicUsage(tx.wit);
+ size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
mem += RecursiveDynamicUsage(*it);
}
@@ -69,8 +53,8 @@ static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) {
static inline size_t RecursiveDynamicUsage(const CBlock& block) {
size_t mem = memusage::DynamicUsage(block.vtx);
- for (std::vector<CTransaction>::const_iterator it = block.vtx.begin(); it != block.vtx.end(); it++) {
- mem += RecursiveDynamicUsage(*it);
+ for (const auto& tx : block.vtx) {
+ mem += memusage::DynamicUsage(tx) + RecursiveDynamicUsage(*tx);
}
return mem;
}
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 7cfda6dd6d..a8d667e3bc 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -20,13 +20,11 @@
#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())
{
@@ -39,7 +37,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 +45,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 +55,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,19 +81,19 @@ CScript ParseScript(const std::string& s)
}
else
{
- throw runtime_error("script parse error");
+ throw std::runtime_error("script parse error");
}
}
return result;
}
-bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx, bool fTryNoWitness)
+bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness)
{
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);
@@ -113,6 +111,8 @@ bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx, bool fTryNoWitne
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> tx;
+ if (!ssData.empty())
+ return false;
}
catch (const std::exception&) {
return false;
@@ -138,9 +138,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 +149,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 6f9e2266a3..d116e617ee 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -18,16 +18,14 @@
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
-using namespace std;
-
-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 +34,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,14 +53,14 @@ string FormatScript(const CScript& script)
return ret.substr(0, ret.size() - 1);
}
-const map<unsigned char, string> mapSigHashTypes =
+const std::map<unsigned char, std::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"))
+ (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"))
;
/**
@@ -72,11 +70,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,12 +85,12 @@ 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
@@ -116,9 +114,9 @@ string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
return str;
}
-string EncodeHexTx(const CTransaction& tx)
+std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags)
{
- CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serializeFlags);
ssTx << tx;
return HexStr(ssTx.begin(), ssTx.end());
}
@@ -127,7 +125,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));
@@ -151,11 +149,15 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
{
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);
- BOOST_FOREACH(const CTxIn& txin, tx.vin) {
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
+ const CTxIn& txin = tx.vin[i];
UniValue in(UniValue::VOBJ);
if (tx.IsCoinBase())
in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
@@ -166,6 +168,13 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true));
o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
in.pushKV("scriptSig", o);
+ if (!tx.vin[i].scriptWitness.IsNull()) {
+ UniValue txinwitness(UniValue::VARR);
+ for (const auto& item : tx.vin[i].scriptWitness.stack) {
+ txinwitness.push_back(HexStr(item.begin(), item.end()));
+ }
+ in.pushKV("txinwitness", txinwitness);
+ }
}
in.pushKV("sequence", (int64_t)txin.nSequence);
vin.push_back(in);
diff --git a/src/crypto/aes.h b/src/crypto/aes.h
index 8cae357c12..e9f1b52e71 100644
--- a/src/crypto/aes.h
+++ b/src/crypto/aes.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
//
diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp
new file mode 100644
index 0000000000..816ae870e1
--- /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 = NULL;
+ 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..bcca3d30ea 100644
--- a/src/crypto/common.h
+++ b/src/crypto/common.h
@@ -10,57 +10,94 @@
#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/ctaes/ctaes.c b/src/crypto/ctaes/ctaes.c
index 2389fc0bb2..55962bf252 100644
--- a/src/crypto/ctaes/ctaes.c
+++ b/src/crypto/ctaes/ctaes.c
@@ -134,7 +134,7 @@ static void SubBytes(AES_state *s, int inv) {
D = U7;
}
- /* Non-linear transformation (identical to the code in SubBytes) */
+ /* Non-linear transformation (shared between the forward and backward case) */
M1 = T13 & T6;
M6 = T3 & T16;
M11 = T1 & T15;
@@ -469,9 +469,9 @@ static void AES_encrypt(const AES_state* rounds, int nrounds, unsigned char* cip
static void AES_decrypt(const AES_state* rounds, int nrounds, unsigned char* plain16, const unsigned char* cipher16) {
/* Most AES decryption implementations use the alternate scheme
- * (the Equivalent Inverse Cipher), which looks more like encryption, but
- * needs different round constants. We can't reuse any code here anyway, so
- * don't bother. */
+ * (the Equivalent Inverse Cipher), which allows for more code reuse between
+ * the encryption and decryption code, but requires separate setup for both.
+ */
AES_state s = {{0}};
int round;
diff --git a/src/crypto/ctaes/test.c b/src/crypto/ctaes/test.c
index fce1696acd..21439a16f1 100644
--- a/src/crypto/ctaes/test.c
+++ b/src/crypto/ctaes/test.c
@@ -102,7 +102,7 @@ int main(void) {
}
}
if (fail == 0) {
- fprintf(stderr, "All tests succesful\n");
+ fprintf(stderr, "All tests successful\n");
} else {
fprintf(stderr, "%i tests failed\n", fail);
}
diff --git a/src/crypto/ripemd160.h b/src/crypto/ripemd160.h
index bd41f02508..38ea375c1f 100644
--- a/src/crypto/ripemd160.h
+++ b/src/crypto/ripemd160.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Bitcoin Core developers
+// Copyright (c) 2014-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.
diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h
index 8fb20810be..8b4568ee12 100644
--- a/src/crypto/sha1.h
+++ b/src/crypto/sha1.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Bitcoin Core developers
+// Copyright (c) 2014-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.
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index 5b15b6a233..127e62a228 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Bitcoin Core developers
+// Copyright (c) 2014-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.
diff --git a/src/crypto/sha512.h b/src/crypto/sha512.h
index 614681fae2..cd1023bc85 100644
--- a/src/crypto/sha512.h
+++ b/src/crypto/sha512.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Bitcoin Core developers
+// Copyright (c) 2014-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.
diff --git a/src/cuckoocache.h b/src/cuckoocache.h
new file mode 100644
index 0000000000..5837549455
--- /dev/null
+++ b/src/cuckoocache.h
@@ -0,0 +1,450 @@
+// Copyright (c) 2016 Jeremy Rubin
+// 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_
+
+#include <array>
+#include <algorithm>
+#include <atomic>
+#include <cstring>
+#include <cmath>
+#include <memory>
+#include <vector>
+
+
+/** namespace CuckooCache provides high performance cache primitives
+ *
+ * Summary:
+ *
+ * 1) bit_packed_atomic_flags is bit-packed atomic flags for garbage collection
+ *
+ * 2) cache is a cache which is performant in memory usage and lookup speed. It
+ * is lockfree for erase operations. Elements are lazily erased on the next
+ * insert.
+ */
+namespace CuckooCache
+{
+/** bit_packed_atomic_flags implements a container for garbage collection flags
+ * that is only thread unsafe on calls to setup. This class bit-packs collection
+ * flags for memory efficiency.
+ *
+ * All operations are std::memory_order_relaxed so external mechanisms must
+ * ensure that writes and reads are properly synchronized.
+ *
+ * On setup(n), all bits up to n are marked as collected.
+ *
+ * Under the hood, because it is an 8-bit type, it makes sense to use a multiple
+ * of 8 for setup, but it will be safe if that is not the case as well.
+ *
+ */
+class bit_packed_atomic_flags
+{
+ std::unique_ptr<std::atomic<uint8_t>[]> mem;
+
+public:
+ /** No default constructor as there must be some size */
+ bit_packed_atomic_flags() = delete;
+
+ /**
+ * bit_packed_atomic_flags constructor creates memory to sufficiently
+ * keep track of garbage collection information for size entries.
+ *
+ * @param size the number of elements to allocate space for
+ *
+ * @post bit_set, bit_unset, and bit_is_set function properly forall x. x <
+ * size
+ * @post All calls to bit_is_set (without subsequent bit_unset) will return
+ * true.
+ */
+ bit_packed_atomic_flags(uint32_t size)
+ {
+ // pad out the size if needed
+ size = (size + 7) / 8;
+ mem.reset(new std::atomic<uint8_t>[size]);
+ for (uint32_t i = 0; i < size; ++i)
+ mem[i].store(0xFF);
+ };
+
+ /** setup marks all entries and ensures that bit_packed_atomic_flags can store
+ * at least size entries
+ *
+ * @param b the number of elements to allocate space for
+ * @post bit_set, bit_unset, and bit_is_set function properly forall x. x <
+ * b
+ * @post All calls to bit_is_set (without subsequent bit_unset) will return
+ * true.
+ */
+ inline void setup(uint32_t b)
+ {
+ bit_packed_atomic_flags d(b);
+ std::swap(mem, d.mem);
+ }
+
+ /** bit_set sets an entry as discardable.
+ *
+ * @param s the index of the entry to bit_set.
+ * @post immediately subsequent call (assuming proper external memory
+ * ordering) to bit_is_set(s) == true.
+ *
+ */
+ inline void bit_set(uint32_t s)
+ {
+ mem[s >> 3].fetch_or(1 << (s & 7), std::memory_order_relaxed);
+ }
+
+ /** bit_unset marks an entry as something that should not be overwritten
+ *
+ * @param s the index of the entry to bit_unset.
+ * @post immediately subsequent call (assuming proper external memory
+ * ordering) to bit_is_set(s) == false.
+ */
+ inline void bit_unset(uint32_t s)
+ {
+ mem[s >> 3].fetch_and(~(1 << (s & 7)), std::memory_order_relaxed);
+ }
+
+ /** bit_is_set queries the table for discardability at s
+ *
+ * @param s the index of the entry to read.
+ * @returns if the bit at index s was set.
+ * */
+ inline bool bit_is_set(uint32_t s) const
+ {
+ return (1 << (s & 7)) & mem[s >> 3].load(std::memory_order_relaxed);
+ }
+};
+
+/** cache implements a cache with properties similar to a cuckoo-set
+ *
+ * The cache is able to hold up to (~(uint32_t)0) - 1 elements.
+ *
+ * Read Operations:
+ * - contains(*, false)
+ *
+ * Read+Erase Operations:
+ * - contains(*, true)
+ *
+ * Erase Operations:
+ * - allow_erase()
+ *
+ * Write Operations:
+ * - setup()
+ * - setup_bytes()
+ * - insert()
+ * - please_keep()
+ *
+ * Synchronization Free Operations:
+ * - invalid()
+ * - compute_hashes()
+ *
+ * User Must Guarantee:
+ *
+ * 1) Write Requires synchronized access (e.g., a lock)
+ * 2) Read Requires no concurrent Write, synchronized with the last insert.
+ * 3) Erase requires no concurrent Write, synchronized with last insert.
+ * 4) An Erase caller must release all memory before allowing a new Writer.
+ *
+ *
+ * Note on function names:
+ * - The name "allow_erase" is used because the real discard happens later.
+ * - The name "please_keep" is used because elements may be erased anyways on insert.
+ *
+ * @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 uint32_t hashes for `Hash h; h<0>(e) ... h<7>(e)`.
+ */
+template <typename Element, typename Hash>
+class cache
+{
+private:
+ /** table stores all the elements */
+ std::vector<Element> table;
+
+ /** size stores the total available slots in the hash table */
+ uint32_t size;
+
+ /** The bit_packed_atomic_flags array is marked mutable because we want
+ * garbage collection to be allowed to occur from const methods */
+ mutable bit_packed_atomic_flags collection_flags;
+
+ /** epoch_flags tracks how recently an element was inserted into
+ * the cache. true denotes recent, false denotes not-recent. See insert()
+ * method for full semantics.
+ */
+ mutable std::vector<bool> epoch_flags;
+
+ /** epoch_heuristic_counter is used to determine when a 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.
+ */
+ 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
+ * 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 --
+ * one "dead" which has been erased, one "dying" which has been marked to be
+ * erased next, and one "living" which new inserts add to.
+ */
+ uint32_t epoch_size;
+
+ /** depth_limit determines how many elements insert should try to replace.
+ * Should be set to log2(n)*/
+ uint8_t depth_limit;
+
+ /** hash_function is a const instance of the hash function. It cannot be
+ * static or initialized at call time as it may have internal state (such as
+ * a nonce).
+ * */
+ const Hash hash_function;
+
+ /** compute_hashes is convenience for not having to write out this
+ * expression everywhere we use the hash values of an Element.
+ *
+ * @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 {{(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
+ * @returns a constexpr index that can never be inserted to */
+ constexpr uint32_t invalid() const
+ {
+ return ~(uint32_t)0;
+ }
+
+ /** allow_erase marks the element at index n as discardable. Threadsafe
+ * without any concurrent insert.
+ * @param n the index to allow erasure of
+ */
+ inline void allow_erase(uint32_t n) const
+ {
+ collection_flags.bit_set(n);
+ }
+
+ /** please_keep marks the element at index n as an entry that should be kept.
+ * Threadsafe without any concurrent insert.
+ * @param n the index to prioritize keeping
+ */
+ inline void please_keep(uint32_t n) const
+ {
+ collection_flags.bit_unset(n);
+ }
+
+ /** epoch_check handles the changing of epochs for elements stored in the
+ * cache. epoch_check should be run before every insert.
+ *
+ * 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 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.
+ */
+ void epoch_check()
+ {
+ if (epoch_heuristic_counter != 0) {
+ --epoch_heuristic_counter;
+ return;
+ }
+ // count the number of elements from the latest epoch which
+ // have not been erased.
+ uint32_t epoch_unused_count = 0;
+ for (uint32_t i = 0; i < size; ++i)
+ epoch_unused_count += epoch_flags[i] &&
+ !collection_flags.bit_is_set(i);
+ // If there are more non-deleted entries in the current epoch than the
+ // epoch size, then allow_erase on all elements in the old epoch (marked
+ // false) and move all elements in the current epoch to the old epoch
+ // but do not call allow_erase on their indices.
+ if (epoch_unused_count >= epoch_size) {
+ for (uint32_t i = 0; i < size; ++i)
+ if (epoch_flags[i])
+ epoch_flags[i] = false;
+ else
+ allow_erase(i);
+ epoch_heuristic_counter = epoch_size;
+ } else
+ // reset the epoch_heuristic_counter to next do a scan when worst
+ // case behavior (no intermittent erases) would exceed epoch size,
+ // with a reasonable minimum scan size.
+ // Ordinarily, we would have to sanity check std::min(epoch_size,
+ // epoch_unused_count), but we already know that `epoch_unused_count
+ // < epoch_size` in this branch
+ epoch_heuristic_counter = std::max(1u, std::max(epoch_size / 16,
+ epoch_size - epoch_unused_count));
+ }
+
+public:
+ /** You must always construct a cache with some elements via a subsequent
+ * call to setup or setup_bytes, otherwise operations may segfault.
+ */
+ cache() : table(), size(), collection_flags(0), epoch_flags(),
+ epoch_heuristic_counter(), epoch_size(), depth_limit(0), hash_function()
+ {
+ }
+
+ /** setup initializes the container to store no more than new_size
+ * elements.
+ *
+ * setup should only be called once.
+ *
+ * @param new_size the desired number of elements to store
+ * @returns the maximum number of elements storable
+ **/
+ uint32_t setup(uint32_t new_size)
+ {
+ // 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 = std::max<uint32_t>(2, new_size);
+ table.resize(size);
+ collection_flags.setup(size);
+ epoch_flags.resize(size);
+ // Set to 45% as described above
+ epoch_size = std::max((uint32_t)1, (45 * size) / 100);
+ // Initially set to wait for a whole epoch
+ epoch_heuristic_counter = epoch_size;
+ return size;
+ }
+
+ /** setup_bytes is a convenience function which accounts for internal memory
+ * usage when deciding how many elements to store. It isn't perfect because
+ * it doesn't account for any overhead (struct size, MallocUsage, collection
+ * and epoch flags). This was done to simplify selecting a power of two
+ * size. In the expected use case, an extra two bits per entry should be
+ * negligible compared to the size of the elements.
+ *
+ * @param bytes the approximate number of bytes to use for this data
+ * structure.
+ * @returns the maximum number of elements storable (see setup()
+ * documentation for more detail)
+ */
+ uint32_t setup_bytes(size_t bytes)
+ {
+ return setup(bytes/sizeof(Element));
+ }
+
+ /** insert loops at most depth_limit times trying to insert a hash
+ * at various locations in the table via a variant of the Cuckoo Algorithm
+ * with eight hash locations.
+ *
+ * It drops the last tried element if it runs out of depth before
+ * encountering an open slot.
+ *
+ * Thus
+ *
+ * insert(x);
+ * return contains(x, false);
+ *
+ * is not guaranteed to return true.
+ *
+ * @param e the element to insert
+ * @post one of the following: All previously inserted elements and e are
+ * now in the table, one previously inserted element is evicted from the
+ * table, the entry attempted to be inserted is evicted.
+ *
+ */
+ inline void insert(Element e)
+ {
+ epoch_check();
+ uint32_t last_loc = invalid();
+ bool last_epoch = true;
+ std::array<uint32_t, 8> locs = compute_hashes(e);
+ // Make sure we have not already inserted this element
+ // If we have, make sure that it does not get deleted
+ for (uint32_t loc : locs)
+ if (table[loc] == e) {
+ please_keep(loc);
+ epoch_flags[loc] = last_epoch;
+ return;
+ }
+ for (uint8_t depth = 0; depth < depth_limit; ++depth) {
+ // First try to insert to an empty slot, if one exists
+ for (uint32_t loc : locs) {
+ if (!collection_flags.bit_is_set(loc))
+ continue;
+ table[loc] = std::move(e);
+ please_keep(loc);
+ epoch_flags[loc] = last_epoch;
+ return;
+ }
+ /** Swap with the element at the location that was
+ * not the last one looked at. Example:
+ *
+ * 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 indices wrapping around
+ * to 0 if needed.
+ *
+ * This prevents moving the element we just put in.
+ *
+ * The swap is not a move -- we must switch onto the evicted element
+ * for the next iteration.
+ */
+ last_loc = locs[(1 + (std::find(locs.begin(), locs.end(), last_loc) - locs.begin())) & 7];
+ std::swap(table[last_loc], e);
+ // Can't std::swap a std::vector<bool>::reference and a bool&.
+ bool epoch = last_epoch;
+ last_epoch = epoch_flags[last_loc];
+ epoch_flags[last_loc] = epoch;
+
+ // Recompute the locs -- unfortunately happens one too many times!
+ locs = compute_hashes(e);
+ }
+ }
+
+ /* contains iterates through the hash locations for a given element
+ * and checks to see if it is present.
+ *
+ * contains does not check garbage collected state (in other words,
+ * garbage is only collected when the space is needed), so:
+ *
+ * insert(x);
+ * if (contains(x, true))
+ * return contains(x, false);
+ * else
+ * return true;
+ *
+ * executed on a single thread will always return true!
+ *
+ * This is a great property for re-org performance for example.
+ *
+ * contains returns a bool set true if the element was found.
+ *
+ * @param e the element to check
+ * @param erase
+ *
+ * @post if erase is true and the element is found, then the garbage collect
+ * flag is set
+ * @returns true if the element is found, false otherwise
+ */
+ inline bool contains(const Element& e, const bool erase) const
+ {
+ std::array<uint32_t, 8> locs = compute_hashes(e);
+ for (uint32_t loc : locs)
+ if (table[loc] == e) {
+ if (erase)
+ allow_erase(loc);
+ return true;
+ }
+ return false;
+ }
+};
+} // namespace CuckooCache
+
+#endif
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 09c68fbe55..3d2098c059 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -1,19 +1,77 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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 "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
+ virtual 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,7 +90,7 @@ 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;
readoptions.verify_checksums = true;
@@ -82,6 +141,8 @@ CDBWrapper::~CDBWrapper()
pdb = NULL;
delete options.filter_policy;
options.filter_policy = NULL;
+ delete options.info_log;
+ options.info_log = NULL;
delete options.block_cache;
options.block_cache = NULL;
delete penv;
@@ -117,7 +178,7 @@ std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
bool CDBWrapper::IsEmpty()
{
- boost::scoped_ptr<CDBIterator> it(NewIterator());
+ std::unique_ptr<CDBIterator> it(NewIterator());
it->SeekToFirst();
return !(it->Valid());
}
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index a0779d3ab9..b13e98b7a4 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -6,17 +6,19 @@
#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>
+static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
+static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
+
class dbwrapper_error : public std::runtime_error
{
public:
@@ -50,38 +52,41 @@ private:
const CDBWrapper &parent;
leveldb::WriteBatch batch;
+ CDataStream ssKey;
+ CDataStream ssValue;
+
public:
/**
- * @param[in] parent CDBWrapper that this batch is to be submitted to
+ * @param[in] _parent CDBWrapper that this batch is to be submitted to
*/
- CDBBatch(const CDBWrapper &parent) : parent(parent) { };
+ CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION) { };
template <typename K, typename V>
void Write(const K& key, const V& value)
{
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- ssKey.reserve(ssKey.GetSerializeSize(key));
+ ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
- leveldb::Slice slKey(&ssKey[0], ssKey.size());
+ leveldb::Slice slKey(ssKey.data(), ssKey.size());
- CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- ssValue.reserve(ssValue.GetSerializeSize(value));
+ ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
ssValue << value;
ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
- leveldb::Slice slValue(&ssValue[0], ssValue.size());
+ leveldb::Slice slValue(ssValue.data(), ssValue.size());
batch.Put(slKey, slValue);
+ ssKey.clear();
+ ssValue.clear();
}
template <typename K>
void Erase(const K& key)
{
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- ssKey.reserve(ssKey.GetSerializeSize(key));
+ ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
- leveldb::Slice slKey(&ssKey[0], ssKey.size());
+ leveldb::Slice slKey(ssKey.data(), ssKey.size());
batch.Delete(slKey);
+ ssKey.clear();
}
};
@@ -94,11 +99,11 @@ private:
public:
/**
- * @param[in] parent Parent CDBWrapper instance.
- * @param[in] piterIn The original leveldb iterator.
+ * @param[in] _parent Parent CDBWrapper instance.
+ * @param[in] _piter The original leveldb iterator.
*/
- CDBIterator(const CDBWrapper &parent, leveldb::Iterator *piterIn) :
- parent(parent), piter(piterIn) { };
+ CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) :
+ parent(_parent), piter(_piter) { };
~CDBIterator();
bool Valid();
@@ -107,9 +112,9 @@ public:
template<typename K> void Seek(const K& key) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- ssKey.reserve(ssKey.GetSerializeSize(key));
+ ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
- leveldb::Slice slKey(&ssKey[0], ssKey.size());
+ leveldb::Slice slKey(ssKey.data(), ssKey.size());
piter->Seek(slKey);
}
@@ -126,10 +131,6 @@ public:
return true;
}
- unsigned int GetKeySize() {
- return piter->key().size();
- }
-
template<typename V> bool GetValue(V& value) {
leveldb::Slice slValue = piter->value();
try {
@@ -193,16 +194,16 @@ 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>
bool Read(const K& key, V& value) const
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- ssKey.reserve(ssKey.GetSerializeSize(key));
+ ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
- leveldb::Slice slKey(&ssKey[0], ssKey.size());
+ leveldb::Slice slKey(ssKey.data(), ssKey.size());
std::string strValue;
leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
@@ -234,9 +235,9 @@ public:
bool Exists(const K& key) const
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- ssKey.reserve(ssKey.GetSerializeSize(key));
+ ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
- leveldb::Slice slKey(&ssKey[0], ssKey.size());
+ leveldb::Slice slKey(ssKey.data(), ssKey.size());
std::string strValue;
leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
diff --git a/src/fs.cpp b/src/fs.cpp
new file mode 100644
index 0000000000..6f2b768de3
--- /dev/null
+++ b/src/fs.cpp
@@ -0,0 +1,17 @@
+#include "fs.h"
+
+#include <boost/filesystem.hpp>
+
+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..585cbf9c38
--- /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
diff --git a/src/hash.cpp b/src/hash.cpp
index 20a83342db..a14a2386a2 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2013-2015 The Bitcoin Core developers
+// Copyright (c) 2013-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.
@@ -57,7 +57,7 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
k1 = ROTL32(k1, 15);
k1 *= c2;
h1 ^= k1;
- };
+ }
}
//----------
diff --git a/src/hash.h b/src/hash.h
index db4e130ae7..eacb8f04fe 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -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) {
@@ -132,15 +132,17 @@ class CHashWriter
private:
CHash256 ctx;
+ const int nType;
+ const int nVersion;
public:
- int nType;
- int nVersion;
CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}
- CHashWriter& write(const char *pch, size_t size) {
+ int GetType() const { return nType; }
+ int GetVersion() const { return nVersion; }
+
+ void write(const char *pch, size_t size) {
ctx.Write((const unsigned char*)pch, size);
- return (*this);
}
// invalidates the object
@@ -153,7 +155,7 @@ public:
template<typename T>
CHashWriter& operator<<(const T& obj) {
// Serialize to this stream
- ::Serialize(*this, obj, nType, nVersion);
+ ::Serialize(*this, obj);
return (*this);
}
};
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 04d3386e9a..18a9819edd 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -25,7 +25,7 @@
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
{
@@ -45,7 +45,7 @@ private:
class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
- HTTPRPCTimerInterface(struct event_base* base) : base(base)
+ HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
{
}
const char* Name()
@@ -93,9 +93,9 @@ 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) {
+ if (gArgs.IsArgSet("-rpcauth")) {
//Search for multi-user login/pass "rpcauth" from config
- BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs["-rpcauth"])
+ BOOST_FOREACH(std::string strRPCAuth, gArgs.GetArgs("-rpcauth"))
{
std::vector<std::string> vFields;
boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
@@ -112,9 +112,9 @@ static bool multiUserAuthorized(std::string strUserPass)
std::string strSalt = vFields[1];
std::string strHash = vFields[2];
- unsigned int KEY_SIZE = 32;
- unsigned char *out = new unsigned char[KEY_SIZE];
-
+ 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);
@@ -127,7 +127,7 @@ static bool multiUserAuthorized(std::string strUserPass)
return false;
}
-static bool RPCAuthorized(const std::string& strAuth)
+static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut)
{
if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
return false;
@@ -136,7 +136,10 @@ static bool RPCAuthorized(const std::string& strAuth)
std::string strUserPass64 = strAuth.substr(6);
boost::trim(strUserPass64);
std::string strUserPass = DecodeBase64(strUserPass64);
-
+
+ if (strUserPass.find(":") != std::string::npos)
+ strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(":"));
+
//Check if authorized under single-user field
if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
return true;
@@ -159,7 +162,8 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
return false;
}
- if (!RPCAuthorized(authHeader.second)) {
+ JSONRPCRequest jreq;
+ if (!RPCAuthorized(authHeader.second, jreq.authUser)) {
LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", req->GetPeer().ToString());
/* Deter brute-forcing
@@ -172,19 +176,21 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
return false;
}
- JSONRequest jreq;
try {
// Parse request
UniValue valRequest;
if (!valRequest.read(req->ReadBody()))
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
+ // Set the URI
+ jreq.URI = req->GetURI();
+
std::string strReply;
// singleton request
if (valRequest.isObject()) {
jreq.parse(valRequest);
- UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
+ UniValue result = tableRPC.execute(jreq);
// Send reply
strReply = JSONRPCReply(result, NullUniValue, jreq.id);
@@ -209,7 +215,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
static bool InitRPCAuthentication()
{
- if (mapArgs["-rpcpassword"] == "")
+ if (GetArg("-rpcpassword", "") == "")
{
LogPrintf("No rpcpassword set - using random cookie authentication\n");
if (!GenerateAuthCookie(&strRPCUserColonPass)) {
@@ -220,14 +226,14 @@ 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 = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
+ strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + 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;
@@ -241,12 +247,12 @@ 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);
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 812940eaf9..0d1cba3fd2 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
+#include <future>
#include <event2/event.h>
#include <event2/http.h>
@@ -34,9 +35,6 @@
#endif
#endif
-#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
-#include <boost/foreach.hpp>
-
/** Maximum size of http request (request line + headers) */
static const size_t MAX_HEADERS_SIZE = 8192;
@@ -44,8 +42,8 @@ static const size_t MAX_HEADERS_SIZE = 8192;
class HTTPWorkItem : public HTTPClosure
{
public:
- HTTPWorkItem(std::unique_ptr<HTTPRequest> req, const std::string &path, const HTTPRequestHandler& func):
- req(std::move(req)), path(path), func(func)
+ HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
+ req(std::move(_req)), path(_path), func(_func)
{
}
void operator()()
@@ -68,8 +66,8 @@ class WorkQueue
{
private:
/** Mutex protects entire object */
- CWaitableCriticalSection cs;
- CConditionVariable cond;
+ std::mutex cs;
+ std::condition_variable cond;
std::deque<std::unique_ptr<WorkItem>> queue;
bool running;
size_t maxDepth;
@@ -82,20 +80,20 @@ private:
WorkQueue &wq;
ThreadCounter(WorkQueue &w): wq(w)
{
- boost::lock_guard<boost::mutex> lock(wq.cs);
+ std::lock_guard<std::mutex> lock(wq.cs);
wq.numThreads += 1;
}
~ThreadCounter()
{
- boost::lock_guard<boost::mutex> lock(wq.cs);
+ std::lock_guard<std::mutex> lock(wq.cs);
wq.numThreads -= 1;
wq.cond.notify_all();
}
};
public:
- WorkQueue(size_t maxDepth) : running(true),
- maxDepth(maxDepth),
+ WorkQueue(size_t _maxDepth) : running(true),
+ maxDepth(_maxDepth),
numThreads(0)
{
}
@@ -108,7 +106,7 @@ public:
/** Enqueue a work item */
bool Enqueue(WorkItem* item)
{
- boost::unique_lock<boost::mutex> lock(cs);
+ std::unique_lock<std::mutex> lock(cs);
if (queue.size() >= maxDepth) {
return false;
}
@@ -120,10 +118,10 @@ public:
void Run()
{
ThreadCounter count(*this);
- while (running) {
+ while (true) {
std::unique_ptr<WorkItem> i;
{
- boost::unique_lock<boost::mutex> lock(cs);
+ std::unique_lock<std::mutex> lock(cs);
while (running && queue.empty())
cond.wait(lock);
if (!running)
@@ -137,31 +135,24 @@ public:
/** Interrupt and exit loops */
void Interrupt()
{
- boost::unique_lock<boost::mutex> lock(cs);
+ std::unique_lock<std::mutex> lock(cs);
running = false;
cond.notify_all();
}
/** Wait for worker threads to exit */
void WaitExit()
{
- boost::unique_lock<boost::mutex> lock(cs);
+ std::unique_lock<std::mutex> lock(cs);
while (numThreads > 0)
cond.wait(lock);
}
-
- /** Return current depth of queue */
- size_t Depth()
- {
- boost::unique_lock<boost::mutex> lock(cs);
- return queue.size();
- }
};
struct HTTPPathHandler
{
HTTPPathHandler() {}
- HTTPPathHandler(std::string prefix, bool exactMatch, HTTPRequestHandler handler):
- prefix(prefix), exactMatch(exactMatch), handler(handler)
+ HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):
+ prefix(_prefix), exactMatch(_exactMatch), handler(_handler)
{
}
std::string prefix;
@@ -189,7 +180,7 @@ static bool ClientAllowed(const CNetAddr& netaddr)
{
if (!netaddr.IsValid())
return false;
- BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets)
+ for(const CSubNet& subnet : rpc_allow_subnets)
if (subnet.Match(netaddr))
return true;
return false;
@@ -199,12 +190,16 @@ static bool ClientAllowed(const CNetAddr& netaddr)
static bool InitHTTPAllowList()
{
rpc_allow_subnets.clear();
- rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet
- rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost
- if (mapMultiArgs.count("-rpcallowip")) {
- const std::vector<std::string>& vAllow = mapMultiArgs["-rpcallowip"];
- BOOST_FOREACH (std::string strAllow, vAllow) {
- CSubNet subnet(strAllow);
+ CNetAddr localv4;
+ CNetAddr localv6;
+ LookupHost("127.0.0.1", localv4, false);
+ 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 (gArgs.IsArgSet("-rpcallowip")) {
+ 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),
@@ -215,9 +210,9 @@ static bool InitHTTPAllowList()
}
}
std::string strAllowed;
- BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets)
+ 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;
}
@@ -247,7 +242,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
@@ -297,18 +292,19 @@ 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");
+ LogPrint(BCLog::HTTP, "Rejecting request while shutting down\n");
evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
}
/** Event dispatcher thread */
-static void ThreadHTTP(struct event_base* base, struct evhttp* http)
+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 */
@@ -318,18 +314,17 @@ static bool HTTPBindAddresses(struct evhttp* http)
std::vector<std::pair<std::string, uint16_t> > endpoints;
// Determine what addresses to bind to
- if (!mapArgs.count("-rpcallowip")) { // Default to loopback if not allowing external IPs
+ if (!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 (mapArgs.count("-rpcbind")) {
+ if (IsArgSet("-rpcbind")) {
LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
}
- } else if (mapArgs.count("-rpcbind")) { // Specific bind address
- const std::vector<std::string>& vbind = mapMultiArgs["-rpcbind"];
- for (std::vector<std::string>::const_iterator i = vbind.begin(); i != vbind.end(); ++i) {
+ } 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
@@ -339,7 +334,7 @@ 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);
+ 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() ? NULL : i->first.c_str(), i->second);
if (bind_handle) {
boundSockets.push_back(bind_handle);
@@ -367,7 +362,7 @@ 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()
@@ -387,14 +382,13 @@ 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
@@ -427,7 +421,7 @@ bool InitHTTPServer()
return false;
}
- LogPrint("http", "Initialized HTTP server\n");
+ LogPrint(BCLog::HTTP, "Initialized HTTP server\n");
int workQueueDepth = std::max((long)GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
@@ -437,26 +431,45 @@ bool InitHTTPServer()
return true;
}
-boost::thread threadHTTP;
+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");
+ LogPrint(BCLog::HTTP, "Starting HTTP server\n");
int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
- threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP));
+ std::packaged_task<bool(event_base*, evhttp*)> task(ThreadHTTP);
+ threadResult = task.get_future();
+ threadHTTP = std::thread(std::move(task), eventBase, eventHTTP);
- for (int i = 0; i < rpcThreads; i++)
- boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue));
+ for (int i = 0; i < rpcThreads; i++) {
+ std::thread rpc_worker(HTTPWorkQueueRun, workQueue);
+ rpc_worker.detach();
+ }
return true;
}
void InterruptHTTPServer()
{
- LogPrint("http", "Interrupting HTTP server\n");
+ LogPrint(BCLog::HTTP, "Interrupting HTTP server\n");
if (eventHTTP) {
// Unlisten sockets
- BOOST_FOREACH (evhttp_bound_socket *socket, boundSockets) {
+ for (evhttp_bound_socket *socket : boundSockets) {
evhttp_del_accept_socket(eventHTTP, socket);
}
// Reject requests on current connections
@@ -468,29 +481,26 @@ 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
// master that appears to be solved, so in the future that solution
// could be used again (if desirable).
// (see discussion in https://github.com/bitcoin/bitcoin/pull/6990)
-#if BOOST_VERSION >= 105000
- if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) {
-#else
- if (!threadHTTP.timed_join(boost::posix_time::milliseconds(2000))) {
-#endif
+ if (threadResult.valid() && threadResult.wait_for(std::chrono::milliseconds(2000)) == std::future_status::timeout) {
LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n");
event_base_loopbreak(eventBase);
- threadHTTP.join();
}
+ threadHTTP.join();
}
if (eventHTTP) {
evhttp_free(eventHTTP);
@@ -500,7 +510,7 @@ void StopHTTPServer()
event_base_free(eventBase);
eventBase = 0;
}
- LogPrint("http", "Stopped HTTP server\n");
+ LogPrint(BCLog::HTTP, "Stopped HTTP server\n");
}
struct event_base* EventBase()
@@ -517,8 +527,8 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data)
delete self;
}
-HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler):
- deleteWhenTriggered(deleteWhenTriggered), handler(handler)
+HTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function<void(void)>& _handler):
+ deleteWhenTriggered(_deleteWhenTriggered), handler(_handler)
{
ev = event_new(base, -1, 0, httpevent_callback_fn, this);
assert(ev);
@@ -534,7 +544,7 @@ void HTTPEvent::trigger(struct timeval* tv)
else
evtimer_add(ev, tv); // trigger after timeval passed
}
-HTTPRequest::HTTPRequest(struct evhttp_request* req) : req(req),
+HTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req),
replySent(false)
{
}
@@ -599,7 +609,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
assert(evb);
evbuffer_add(evb, strReply.data(), strReply.size());
HTTPEvent* ev = new HTTPEvent(eventBase, true,
- boost::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
+ std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
ev->trigger(0);
replySent = true;
req = 0; // transferred back to main thread
@@ -614,7 +624,7 @@ CService HTTPRequest::GetPeer()
const char* address = "";
uint16_t port = 0;
evhttp_connection_get_peer(con, (char**)&address, &port);
- peer = CService(address, port);
+ peer = LookupNumeric(address, port);
}
return peer;
}
@@ -647,7 +657,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));
}
@@ -660,7 +670,7 @@ 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);
}
}
diff --git a/src/httpserver.h b/src/httpserver.h
index 20a119cc5c..6be9950682 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -7,9 +7,7 @@
#include <string>
#include <stdint.h>
-#include <boost/thread.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/function.hpp>
+#include <functional>
static const int DEFAULT_HTTP_THREADS=4;
static const int DEFAULT_HTTP_WORKQUEUE=16;
@@ -34,8 +32,12 @@ 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 boost::function<void(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
+typedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
/** Register handler for prefix.
* If multiple handlers match a prefix, the first-registered one will
* be invoked.
@@ -132,7 +134,7 @@ public:
* deleteWhenTriggered deletes this event object after the event is triggered (and the handler called)
* handler is the handler to call when the event is triggered.
*/
- HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler);
+ HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void(void)>& handler);
~HTTPEvent();
/** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after
@@ -141,7 +143,7 @@ public:
void trigger(struct timeval* tv);
bool deleteWhenTriggered;
- boost::function<void(void)> handler;
+ std::function<void(void)> handler;
private:
struct event* ev;
};
diff --git a/src/indirectmap.h b/src/indirectmap.h
index 28e1e8dedd..76da4a6bd5 100644
--- a/src/indirectmap.h
+++ b/src/indirectmap.h
@@ -1,3 +1,7 @@
+// Copyright (c) 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_INDIRECTMAP_H
#define BITCOIN_INDIRECTMAP_H
diff --git a/src/init.cpp b/src/init.cpp
index 509bc45f51..93b4c80c01 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -16,15 +16,21 @@
#include "checkpoints.h"
#include "compat/sanity.h"
#include "consensus/validation.h"
+#include "fs.h"
#include "httpserver.h"
#include "httprpc.h"
#include "key.h"
-#include "main.h"
+#include "validation.h"
#include "miner.h"
+#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/blockchain.h"
#include "script/standard.h"
#include "script/sigcache.h"
#include "scheduler.h"
@@ -39,8 +45,10 @@
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
#endif
+#include "warnings.h"
#include <stdint.h>
#include <stdio.h>
+#include <memory>
#ifndef WIN32
#include <signal.h>
@@ -51,7 +59,6 @@
#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>
@@ -61,14 +68,14 @@
#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;
@@ -114,16 +121,13 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
// 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.
//
std::atomic<bool> fRequestShutdown(false);
+std::atomic<bool> fDumpMempoolLater(false);
void StartShutdown()
{
@@ -161,7 +165,7 @@ public:
static CCoinsViewDB *pcoinsdbview = NULL;
static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
-static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle;
+static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
void Interrupt(boost::thread_group& threadGroup)
{
@@ -170,6 +174,8 @@ void Interrupt(boost::thread_group& threadGroup)
InterruptRPC();
InterruptREST();
InterruptTorControl();
+ if (g_connman)
+ g_connman->Interrupt();
threadGroup.interrupt_all();
}
@@ -181,7 +187,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.
@@ -196,16 +202,23 @@ void Shutdown()
if (pwalletMain)
pwalletMain->Flush(false);
#endif
- StopNode();
+ MapPort(false);
+ UnregisterValidationInterface(peerLogic.get());
+ peerLogic.reset();
+ g_connman.reset();
+
StopTorControl();
UnregisterNodeSignals(GetNodeSignals());
+ if (fDumpMempoolLater && 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);
+ 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;
@@ -240,8 +253,8 @@ void Shutdown()
#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
@@ -256,64 +269,86 @@ 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(const CService &addr, unsigned int flags) {
+#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, NULL);
+}
+#endif
+
+bool static Bind(CConnman& connman, 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 (!connman.BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
if (flags & BF_REPORT_ERROR)
return InitError(strError);
return false;
}
return true;
}
+void OnRPCStarted()
+{
+ uiInterface.NotifyBlockTip.connect(&RPCNotifyBlockChange);
+}
void OnRPCStopped()
{
+ uiInterface.NotifyBlockTip.disconnect(&RPCNotifyBlockChange);
+ RPCNotifyBlockChange(false, nullptr);
cvBlockChange.notify_all();
- LogPrint("rpc", "RPC stopped.\n");
+ LogPrint(BCLog::RPC, "RPC stopped.\n");
}
void OnRPCPreCommand(const CRPCCommand& cmd)
{
// Observe safe mode
- string strWarning = GetWarnings("rpc");
+ std::string strWarning = GetWarnings("rpc");
if (strWarning != "" && !GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE) &&
!cmd.okSafeMode)
- throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
+ throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + strWarning);
}
std::string HelpMessage(HelpMessageMode mode)
{
+ 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 = 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("-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("-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)
{
-#ifndef WIN32
+#if HAVE_DECL_DAEMON
strUsage += HelpMessageOpt("-daemon", _("Run in the background as a daemon and accept commands"));
#endif
}
@@ -325,14 +360,16 @@ 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));
+ 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
strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), BITCOIN_PID_FILENAME));
#endif
- strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. "
+ strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("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, >%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
+ "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
strUsage += HelpMessageOpt("-reindex-chainstate", _("Rebuild chain state from the currently indexed blocks"));
strUsage += HelpMessageOpt("-reindex", _("Rebuild chain state and block index from the blk*.dat files on disk"));
#ifndef WIN32
@@ -345,10 +382,10 @@ 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)"));
+ 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)"));
+ 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)"));
@@ -361,7 +398,7 @@ 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("-seednode=<ip>", _("Connect to a node to retrieve peer addresses, and disconnect"));
@@ -376,10 +413,8 @@ std::string HelpMessage(HelpMessageMode mode)
#endif
#endif
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
- strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
+ 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 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
@@ -398,26 +433,27 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-uacomment=<cmt>", _("Append comment to the user agent string"));
if (showDebug)
{
- 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("-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)", 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("-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)");
}
- string debugCategories = "addrman, alert, bench, 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));
@@ -425,49 +461,53 @@ 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("-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)"));
AppendParamsHelpMessages(strUsage, showDebug);
strUsage += HelpMessageGroup(_("Node relay options:"));
- if (showDebug)
- strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard()));
- strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Minimum bytes per sigop in transactions we relay and mine (default: %u)"), DEFAULT_BYTES_PER_SIGOP));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", defaultChainParams->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("-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("-blockmaxcost=<n>", strprintf(_("Set maximum BIP141 block cost (default: %d)"), DEFAULT_BLOCK_MAX_COST));
+ 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("-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");
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. 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("-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)"), 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));
@@ -481,7 +521,7 @@ std::string LicenseInfo()
{
const std::string URL_SOURCE_CODE = "<https://github.com/bitcoin/bitcoin>";
const std::string URL_WEBSITE = "<https://bitcoincore.org>";
- // todo: remove urls from translations on next change
+
return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2009, COPYRIGHT_YEAR) + " ") + "\n" +
"\n" +
strprintf(_("Please contribute if you find %s useful. "
@@ -493,9 +533,9 @@ std::string LicenseInfo()
"\n" +
"\n" +
_("This is experimental software.") + "\n" +
- _("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.") + "\n" +
+ strprintf(_("Distributed under the MIT software license, see the accompanying file %s or %s"), "COPYING", "<https://opensource.org/licenses/MIT>") + "\n" +
"\n" +
- _("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.") +
+ strprintf(_("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."), "<https://www.openssl.org>") +
"\n";
}
@@ -510,6 +550,21 @@ static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex
boost::thread t(runCommand, strCmd); // thread runs free
}
+static bool fHaveGenesis = false;
+static boost::mutex cs_GenesisWait;
+static CConditionVariable condvar_GenesisWait;
+
+static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex)
+{
+ if (pBlockIndex != NULL) {
+ {
+ boost::unique_lock<boost::mutex> lock_GenesisWait(cs_GenesisWait);
+ fHaveGenesis = true;
+ }
+ condvar_GenesisWait.notify_all();
+ }
+}
+
struct CImportingNow
{
CImportingNow() {
@@ -532,15 +587,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")
@@ -557,7 +611,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) {
+ BOOST_FOREACH(const PAIRTYPE(std::string, fs::path)& item, mapBlockFiles) {
if (atoi(item.first) == nContigCounter) {
nContigCounter++;
continue;
@@ -566,10 +620,12 @@ void CleanupBlockRevFiles()
}
}
-void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
+void ThreadImport(std::vector<fs::path> vImportFiles)
{
const CChainParams& chainparams = Params();
RenameThread("bitcoin-loadblk");
+
+ {
CImportingNow imp;
// -reindex
@@ -577,7 +633,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)
@@ -594,11 +650,11 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
}
// 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);
@@ -608,8 +664,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");
+ BOOST_FOREACH(const fs::path& path, vImportFiles) {
+ FILE *file = fsbridge::fopen(path, "rb");
if (file) {
LogPrintf("Importing blocks file %s...\n", path.string());
LoadExternalBlockFile(chainparams, file);
@@ -629,6 +685,11 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
LogPrintf("Stopping after block import\n");
StartShutdown();
}
+ } // End scope of CImportingNow
+ if (GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
+ LoadMempool();
+ fDumpMempoolLater = !fRequestShutdown;
+ }
}
/** Sanity checks
@@ -641,14 +702,21 @@ 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;
}
bool AppInitServers(boost::thread_group& threadGroup)
{
+ RPCServer::OnStarted(&OnRPCStarted);
RPCServer::OnStopped(&OnRPCStopped);
RPCServer::OnPreCommand(&OnRPCPreCommand);
if (!InitHTTPServer())
@@ -669,16 +737,16 @@ void InitParameterInteraction()
{
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
- if (mapArgs.count("-bind")) {
+ if (IsArgSet("-bind")) {
if (SoftSetBoolArg("-listen", true))
LogPrintf("%s: parameter interaction: -bind set -> setting -listen=1\n", __func__);
}
- if (mapArgs.count("-whitebind")) {
+ if (IsArgSet("-whitebind")) {
if (SoftSetBoolArg("-listen", true))
LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__);
}
- if (mapArgs.count("-connect") && mapMultiArgs["-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))
LogPrintf("%s: parameter interaction: -connect set -> setting -dnsseed=0\n", __func__);
@@ -686,7 +754,7 @@ void InitParameterInteraction()
LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__);
}
- if (mapArgs.count("-proxy")) {
+ if (IsArgSet("-proxy")) {
// to protect privacy, do not listen by default if a default proxy server is specified
if (SoftSetBoolArg("-listen", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__);
@@ -709,32 +777,16 @@ void InitParameterInteraction()
LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__);
}
- if (mapArgs.count("-externalip")) {
+ if (IsArgSet("-externalip")) {
// if an explicit public IP is specified, do not try to find others
if (SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__);
}
- if (GetBoolArg("-salvagewallet", false)) {
- // Rewrite just private keys: rescan to find transactions
- if (SoftSetBoolArg("-rescan", true))
- LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
- }
-
- // -zapwallettx implies a rescan
- if (GetBoolArg("-zapwallettxes", false)) {
- if (SoftSetBoolArg("-rescan", true))
- LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
- }
-
- // disable walletbroadcast and whitelistrelay in blocksonly mode
+ // disable whitelistrelay in blocksonly mode
if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
if (SoftSetBoolArg("-whitelistrelay", false))
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__);
-#ifdef ENABLE_WALLET
- if (SoftSetBoolArg("-walletbroadcast", false))
- LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
-#endif
}
// Forcing relay from whitelisted hosts implies we will accept relays from them in the first place.
@@ -760,10 +812,30 @@ void InitLogging()
LogPrintf("Bitcoin version %s\n", FormatFullVersion());
}
-/** Initialize bitcoin.
- * @pre Parameters should be parsed and config file should be read.
- */
-bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
+namespace { // Variables internal to initialization process only
+
+ServiceFlags nRelevantServices = NODE_NETWORK;
+int nMaxConnections;
+int nUserMaxConnections;
+int nFD;
+ServiceFlags nLocalServices = NODE_NETWORK;
+
+}
+
+[[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()
{
// ********************************************************* Step 1: setup
#ifdef _MSC_VER
@@ -793,78 +865,90 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
return InitError("Initializing networking failed");
#ifndef WIN32
- if (GetBoolArg("-sysperms", false)) {
-#ifdef ENABLE_WALLET
- if (!GetBoolArg("-disablewallet", false))
- return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
-#endif
- } else {
+ if (!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
- // ********************************************************* Step 2: parameter interactions
+ std::set_new_handler(new_handler_terminate);
+
+ return true;
+}
+
+bool AppInitParameterInteraction()
+{
const CChainParams& chainparams = Params();
+ // ********************************************************* Step 2: parameter interactions
// also see: InitParameterInteraction()
- // if using block pruning, then disable txindex
+ // if using block pruning, then disallow txindex
if (GetArg("-prune", 0)) {
if (GetBoolArg("-txindex", DEFAULT_TXINDEX))
return InitError(_("Prune mode is incompatible with -txindex."));
-#ifdef ENABLE_WALLET
- if (GetBoolArg("-rescan", false)) {
- return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
- }
-#endif
}
// Make sure enough file descriptors are available
- int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
- int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
+ int nBind = std::max(
+ (gArgs.IsArgSet("-bind") ? gArgs.GetArgs("-bind").size() : 0) +
+ (gArgs.IsArgSet("-whitebind") ? gArgs.GetArgs("-whitebind").size() : 0), size_t(1));
+ nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
nMaxConnections = std::max(nUserMaxConnections, 0);
// Trim requested connection counts, to fit into system limitations
- nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
- int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
+ nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS)), 0);
+ nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS);
if (nFD < MIN_CORE_FILEDESCRIPTORS)
return InitError(_("Not enough file descriptors available."));
- nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections);
+ nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections);
if (nMaxConnections < nUserMaxConnections)
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["-debug"].empty();
- // Special-case: if -debug=0/-nodebug is set, turn off debugging messages
- const vector<string>& categories = mapMultiArgs["-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
+ if (gArgs.IsArgSet("-debugexclude")) {
+ 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))
InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net."));
// Check for -socks - as this is a privacy risk to continue, exit here
- if (mapArgs.count("-socks"))
+ if (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))
@@ -876,7 +960,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (GetBoolArg("-whitelistalwaysrelay", false))
InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay."));
- if (mapArgs.count("-blockminsize"))
+ if (IsArgSet("-blockminsize"))
InitWarning("Unsupported argument -blockminsize ignored.");
// Checkmempool and checkblockindex default to true in regtest mode
@@ -887,11 +971,26 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
fCheckpointsEnabled = GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
+ hashAssumeValid = uint256S(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");
+
// mempool limits
int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
int64_t nMempoolSizeMin = 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 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"))
+ {
+ CAmount n = 0;
+ if (!ParseMoney(GetArg("-incrementalrelayfee", ""), n))
+ return InitError(AmountErrMsg("incrementalrelayfee", GetArg("-incrementalrelayfee", "")));
+ incrementalRelayFee = CFeeRate(n);
+ }
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
@@ -902,15 +1001,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
- fServer = GetBoolArg("-server", false);
-
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
- int64_t nSignedPruneTarget = GetArg("-prune", 0) * 1024 * 1024;
- if (nSignedPruneTarget < 0) {
+ int64_t nPruneArg = GetArg("-prune", 0);
+ if (nPruneArg < 0) {
return InitError(_("Prune cannot be configured with a negative value."));
}
- nPruneTarget = (uint64_t) nSignedPruneTarget;
- if (nPruneTarget) {
+ nPruneTarget = (uint64_t) nPruneArg * 1024 * 1024;
+ if (nPruneArg == 1) { // manual pruning: -prune=1
+ LogPrintf("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files.\n");
+ nPruneTarget = std::numeric_limits<uint64_t>::max();
+ fPruneMode = true;
+ } else if (nPruneTarget) {
if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
}
@@ -920,39 +1021,61 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
RegisterAllCoreRPCCommands(tableRPC);
#ifdef ENABLE_WALLET
- bool fDisableWallet = GetBoolArg("-disablewallet", false);
- if (!fDisableWallet)
- RegisterWalletRPCCommands(tableRPC);
+ RegisterWalletRPCCommands(tableRPC);
#endif
nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
if (nConnectTimeout <= 0)
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
- // Fee-per-kilobyte amount considered the same as "free"
+ // Fee-per-kilobyte amount required for mempool acceptance and relay
// 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
+ // 0-fee transactions. It should be set above the real
// cost to you of processing a transaction.
- if (mapArgs.count("-minrelaytxfee"))
+ if (IsArgSet("-minrelaytxfee"))
{
CAmount n = 0;
- if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0)
- ::minRelayTxFee = CFeeRate(n);
- else
- return InitError(AmountErrMsg("minrelaytxfee", mapArgs["-minrelaytxfee"]));
+ if (!ParseMoney(GetArg("-minrelaytxfee", ""), n)) {
+ return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", "")));
+ }
+ // High fee check is done afterward in CWallet::ParameterInteraction()
+ ::minRelayTxFee = CFeeRate(n);
+ } else if (incrementalRelayFee > ::minRelayTxFee) {
+ // Allow only setting incrementalRelayFee to control both
+ ::minRelayTxFee = incrementalRelayFee;
+ LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n",::minRelayTxFee.ToString());
}
- fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard());
- if (Params().RequireStandard() && !fRequireStandard)
+ // 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"))
+ {
+ CAmount n = 0;
+ if (!ParseMoney(GetArg("-blockmintxfee", ""), n))
+ return InitError(AmountErrMsg("blockmintxfee", GetArg("-blockmintxfee", "")));
+ }
+
+ // Feerate used to define dust. Shouldn't be changed lightly as old
+ // implementations may inadvertently create non-standard transactions
+ if (IsArgSet("-dustrelayfee"))
+ {
+ CAmount n = 0;
+ if (!ParseMoney(GetArg("-dustrelayfee", ""), n) || 0 == n)
+ return InitError(AmountErrMsg("dustrelayfee", GetArg("-dustrelayfee", "")));
+ dustRelayFee = CFeeRate(n);
+ }
+
+ fRequireStandard = !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);
#ifdef ENABLE_WALLET
if (!CWallet::ParameterInteraction())
return false;
-#endif // ENABLE_WALLET
+#endif
fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
@@ -964,10 +1087,16 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
+ if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0)
+ return InitError("rpcserialversion must be non-negative.");
+
+ if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1)
+ return InitError("unknown rpcserialversion requested.");
+
nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT);
- if ((!fEnableReplacement) && mapArgs.count("-mempoolreplacement")) {
+ if ((!fEnableReplacement) && IsArgSet("-mempoolreplacement")) {
// Minimal effort at forwards compatibility
std::string strReplacementModeList = GetArg("-mempoolreplacement", ""); // default is impossible
std::vector<std::string> vstrReplacementModes;
@@ -975,36 +1104,101 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end());
}
- // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
-
- // Initialize elliptic curve code
- ECC_Start();
- globalVerifyHandle.reset(new ECCVerifyHandle());
-
- // Sanity check
- if (!InitSanityCheck())
- return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
+ if (gArgs.IsArgSet("-bip9params")) {
+ // Allow overriding BIP9 parameters for testing
+ if (!chainparams.MineBlocksOnDemand()) {
+ return InitError("BIP9 parameters may only be overridden on regtest.");
+ }
+ for (const std::string& strDeployment : gArgs.GetArgs("-bip9params")) {
+ std::vector<std::string> vDeploymentParams;
+ boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":"));
+ if (vDeploymentParams.size() != 3) {
+ return InitError("BIP9 parameters malformed, expecting deployment:start:end");
+ }
+ int64_t nStartTime, nTimeout;
+ if (!ParseInt64(vDeploymentParams[1], &nStartTime)) {
+ return InitError(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1]));
+ }
+ if (!ParseInt64(vDeploymentParams[2], &nTimeout)) {
+ return InitError(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2]));
+ }
+ bool found = false;
+ for (int j=0; j<(int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j)
+ {
+ if (vDeploymentParams[0].compare(VersionBitsDeploymentInfo[j].name) == 0) {
+ UpdateBIP9Parameters(Consensus::DeploymentPos(j), nStartTime, nTimeout);
+ found = true;
+ LogPrintf("Setting BIP9 activation parameters for %s to start=%ld, timeout=%ld\n", vDeploymentParams[0], nStartTime, nTimeout);
+ break;
+ }
+ }
+ if (!found) {
+ return InitError(strprintf("Invalid deployment (%s)", vDeploymentParams[0]));
+ }
+ }
+ }
+ return true;
+}
+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 {
static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
- if (!lock.try_lock())
+ if (!lock.try_lock()) {
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), strDataDir, _(PACKAGE_NAME)));
+ }
+ if (probeOnly) {
+ lock.unlock();
+ }
} catch(const boost::interprocess::interprocess_exception& e) {
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.") + " %s.", strDataDir, _(PACKAGE_NAME), e.what()));
}
+ return true;
+}
+
+bool AppInitSanityChecks()
+{
+ // ********************************************************* Step 4: sanity checks
+
+ // Initialize elliptic curve code
+ ECC_Start();
+ globalVerifyHandle.reset(new ECCVerifyHandle());
+
+ // Sanity check
+ if (!InitSanityCheck())
+ 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
+ return LockDataDirectory(true);
+}
+
+bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
+{
+ 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.
+ if (!LockDataDirectory(false)) {
+ // Detailed error printed inside LockDataDirectory
+ return false;
+ }
#ifndef WIN32
CreatePidFile(GetPidFile(), getpid());
#endif
- if (GetBoolArg("-shrinkdebugfile", !fDebug))
+ if (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();
@@ -1012,10 +1206,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!fLogTimestamps)
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", strDataDir);
- LogPrintf("Using config file %s\n", GetConfigFile().string());
- LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD);
- std::ostringstream strErrors;
+ LogPrintf("Using data directory %s\n", GetDataDir().string());
+ LogPrintf("Using config file %s\n", GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string());
+ LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD);
+
+ InitSignatureCache();
LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);
if (nScriptCheckThreads) {
@@ -1032,7 +1227,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
* that the server is there and will be ready later). Warmup mode will
* be disabled when initialisation is finished.
*/
- if (fServer)
+ if (GetBoolArg("-server", false))
{
uiInterface.InitMessage.connect(SetRPCWarmupStatus);
if (!AppInitServers(threadGroup))
@@ -1043,22 +1238,32 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 5: verify wallet database integrity
#ifdef ENABLE_WALLET
- if (!fDisableWallet) {
- if (!CWallet::Verify())
- return false;
- } // (!fDisableWallet)
-#endif // ENABLE_WALLET
+ if (!CWallet::Verify())
+ return false;
+#endif
// ********************************************************* Step 6: network initialization
+ // Note that we absolutely cannot open any actual connections
+ // until the very end ("start node") as the UTXO/block state
+ // is not yet setup and may end up being set up twice if we
+ // need to reindex later.
+
+ assert(!g_connman);
+ g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
+ CConnman& connman = *g_connman;
+ 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;
- BOOST_FOREACH(string cmt, mapMultiArgs["-uacomment"])
- {
- if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
- return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt));
- uacomments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT));
+ std::vector<std::string> uacomments;
+ if (gArgs.IsArgSet("-uacomment")) {
+ BOOST_FOREACH(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) {
@@ -1066,9 +1271,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
strSubVersion.size(), MAX_SUBVERSION_LENGTH));
}
- if (mapArgs.count("-onlynet")) {
+ if (gArgs.IsArgSet("-onlynet")) {
std::set<enum Network> nets;
- BOOST_FOREACH(const std::string& snet, mapMultiArgs["-onlynet"]) {
+ BOOST_FOREACH(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));
@@ -1081,24 +1286,33 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- if (mapArgs.count("-whitelist")) {
- BOOST_FOREACH(const std::string& net, mapMultiArgs["-whitelist"]) {
- CSubNet subnet(net);
+ if (gArgs.IsArgSet("-whitelist")) {
+ BOOST_FOREACH(const std::string& net, gArgs.GetArgs("-whitelist")) {
+ CSubNet subnet;
+ LookupSubNet(net.c_str(), subnet);
if (!subnet.IsValid())
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
- CNode::AddWhitelistedRange(subnet);
+ connman.AddWhitelistedRange(subnet);
}
}
+ // Check for host lookup allowed before parsing any network related parameters
+ fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
+
bool proxyRandomize = 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", "");
SetLimited(NET_TOR);
if (proxyArg != "" && proxyArg != "0") {
- proxyType addrProxy = proxyType(CService(proxyArg, 9050), 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);
@@ -1115,9 +1329,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (onionArg == "0") { // Handle -noonion/-onion=0
SetLimited(NET_TOR); // set onions as unreachable
} else {
- proxyType addrOnion = proxyType(CService(onionArg, 9050), 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);
}
@@ -1126,39 +1344,40 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// 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);
- bool fBound = false;
if (fListen) {
- if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
- BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) {
+ bool fBound = false;
+ if (gArgs.IsArgSet("-bind")) {
+ BOOST_FOREACH(const std::string& strBind, gArgs.GetArgs("-bind")) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
return InitError(ResolveErrMsg("bind", strBind));
- fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
+ fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
- BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) {
+ }
+ if (gArgs.IsArgSet("-whitebind")) {
+ BOOST_FOREACH(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));
- fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
+ fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
}
}
- else {
+ if (!gArgs.IsArgSet("-bind") && !gArgs.IsArgSet("-whitebind")) {
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);
+ 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 (mapArgs.count("-externalip")) {
- BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-externalip"]) {
+ if (gArgs.IsArgSet("-externalip")) {
+ BOOST_FOREACH(const std::string& strAddr, gArgs.GetArgs("-externalip")) {
CService addrLocal;
if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
AddLocal(addrLocal, LOCAL_MANUAL);
@@ -1167,18 +1386,23 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"])
- AddOneShot(strDest);
+ if (gArgs.IsArgSet("-seednode")) {
+ BOOST_FOREACH(const std::string& strDest, gArgs.GetArgs("-seednode"))
+ connman.AddOneShot(strDest);
+ }
#if ENABLE_ZMQ
- pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs);
+ pzmqNotificationInterface = CZMQNotificationInterface::Create();
if (pzmqNotificationInterface) {
RegisterValidationInterface(pzmqNotificationInterface);
}
#endif
- if (mapArgs.count("-maxuploadtarget")) {
- CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024);
+ 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;
}
// ********************************************************* Step 7: load block chain
@@ -1186,37 +1410,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
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;
- }
- }
+ fs::create_directories(GetDataDir() / "blocks");
// cache size calculations
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
- nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache
+ 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);
nTotalCache -= nBlockTreeDBCache;
@@ -1224,10 +1423,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
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;
LogPrintf("Cache configuration:\n");
LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
- LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024));
+ 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) {
@@ -1257,7 +1457,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
CleanupBlockRevFiles();
}
- if (!LoadBlockIndex()) {
+ if (!LoadBlockIndex(chainparams)) {
strLoadError = _("Error loading block database");
break;
}
@@ -1286,7 +1486,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
break;
}
- if (!fReindex) {
+ if (!fReindex && chainActive.Tip() != NULL) {
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");
@@ -1303,6 +1503,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
{
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. "
@@ -1317,7 +1518,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
break;
}
} catch (const std::exception& e) {
- if (fDebug) LogPrintf("%s\n", e.what());
+ LogPrintf("%s\n", e.what());
strLoadError = _("Error opening block database");
break;
}
@@ -1355,26 +1556,20 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
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 (fDisableWallet) {
- pwalletMain = NULL;
- LogPrintf("Wallet disabled!\n");
- } else {
- CWallet::InitLoadWallet();
- if (!pwalletMain)
- return false;
- }
-#else // ENABLE_WALLET
+ if (!CWallet::InitLoadWallet())
+ return false;
+#else
LogPrintf("No wallet support compiled in!\n");
-#endif // !ENABLE_WALLET
+#endif
// ********************************************************* Step 9: data directory maintenance
@@ -1389,8 +1584,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- if (Params().GetConsensus().vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) {
- // Only advertize witness capabilities if they have a reasonable start time.
+ if (chainparams.GetConsensus().vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) {
+ // 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
@@ -1403,51 +1598,69 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 10: import blocks
- if (mapArgs.count("-blocknotify"))
+ if (!CheckDiskSpace())
+ return false;
+
+ // 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) {
+ uiInterface.NotifyBlockTip.connect(BlockNotifyGenesisWait);
+ } else {
+ fHaveGenesis = true;
+ }
+
+ if (IsArgSet("-blocknotify"))
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
- std::vector<boost::filesystem::path> vImportFiles;
- if (mapArgs.count("-loadblock"))
+ std::vector<fs::path> vImportFiles;
+ if (gArgs.IsArgSet("-loadblock"))
{
- BOOST_FOREACH(const std::string& strFile, mapMultiArgs["-loadblock"])
+ BOOST_FOREACH(const std::string& strFile, gArgs.GetArgs("-loadblock"))
vImportFiles.push_back(strFile);
}
+
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
// Wait for genesis block to be processed
- bool fHaveGenesis = false;
- while (!fHaveGenesis && !fRequestShutdown) {
- {
- LOCK(cs_main);
- fHaveGenesis = (chainActive.Tip() != NULL);
- }
-
- if (!fHaveGenesis) {
- MilliSleep(10);
+ {
+ boost::unique_lock<boost::mutex> lock(cs_GenesisWait);
+ while (!fHaveGenesis) {
+ condvar_GenesisWait.wait(lock);
}
+ uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait);
}
// ********************************************************* Step 11: start node
- if (!CheckDiskSpace())
- return false;
-
- if (!strErrors.str().empty())
- return InitError(strErrors.str());
-
//// debug print
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
LogPrintf("nBestHeight = %d\n", chainActive.Height());
-#ifdef ENABLE_WALLET
- LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0);
- LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0);
- LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
-#endif
-
if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl(threadGroup, scheduler);
- StartNode(threadGroup, scheduler);
+ Discover(threadGroup);
+
+ // Map ports with UPnP
+ MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
+
+ std::string strNodeError;
+ CConnman::Options connOptions;
+ connOptions.nLocalServices = nLocalServices;
+ connOptions.nRelevantServices = nRelevantServices;
+ connOptions.nMaxConnections = nMaxConnections;
+ connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections);
+ connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS;
+ connOptions.nMaxFeeler = 1;
+ connOptions.nBestHeight = chainActive.Height();
+ connOptions.uiInterface = &uiInterface;
+ connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
+ connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
+
+ connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe;
+ connOptions.nMaxOutboundLimit = nMaxOutboundLimit;
+
+ if (!connman.Start(scheduler, strNodeError, connOptions))
+ return InitError(strNodeError);
// ********************************************************* Step 12: finished
@@ -1455,13 +1668,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
uiInterface.InitMessage(_("Done loading"));
#ifdef ENABLE_WALLET
- if (pwalletMain) {
- // Add wallet transactions that aren't already in a block to mapTransactions
- pwalletMain->ReacceptWalletTransactions();
-
- // Run a thread to flush wallet periodically
- threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
- }
+ if (pwalletMain)
+ pwalletMain->postInitProcess(scheduler);
#endif
return !fRequestShutdown;
diff --git a/src/init.h b/src/init.h
index 63e07ccb3c..8222794374 100644
--- a/src/init.h
+++ b/src/init.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -25,7 +25,30 @@ void Shutdown();
void InitLogging();
//!Parameter interaction: change current parameters depending on various rules
void InitParameterInteraction();
-bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler);
+
+/** Initialize bitcoin core: Basic context setup.
+ * @note This can be done before daemonization.
+ * @pre Parameters should be parsed and config file should be read.
+ */
+bool AppInitBasicSetup();
+/**
+ * Initialization: parameter interaction.
+ * @note This can be done before daemonization.
+ * @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.
+ * @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.
+ * @pre Parameters should be parsed and config file should be read, AppInitSanityChecks should have been called.
+ */
+bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler);
/** The help message mode determines what help message to show */
enum HelpMessageMode {
diff --git a/src/key.cpp b/src/key.cpp
index 79023566c3..5a75647f1a 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -125,20 +125,12 @@ bool CKey::Check(const unsigned char *vch) {
void CKey::MakeNewKey(bool fCompressedIn) {
do {
- GetStrongRandBytes(vch, sizeof(vch));
- } while (!Check(vch));
+ GetStrongRandBytes(keydata.data(), keydata.size());
+ } while (!Check(keydata.data()));
fValid = true;
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;
@@ -224,41 +216,37 @@ bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
assert(IsValid());
assert(IsCompressed());
- unsigned char out[64];
- LockObject(out);
+ std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);
if ((nChild >> 31) == 0) {
CPubKey pubkey = GetPubKey();
assert(pubkey.begin() + 33 == pubkey.end());
- BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, out);
+ BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, vout.data());
} else {
assert(begin() + 32 == end());
- BIP32Hash(cc, nChild, 0, begin(), out);
+ BIP32Hash(cc, nChild, 0, begin(), vout.data());
}
- memcpy(ccChild.begin(), out+32, 32);
+ memcpy(ccChild.begin(), vout.data()+32, 32);
memcpy((unsigned char*)keyChild.begin(), begin(), 32);
- bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), out);
- UnlockObject(out);
+ bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), vout.data());
keyChild.fCompressed = true;
keyChild.fValid = ret;
return ret;
}
-bool CExtKey::Derive(CExtKey &out, unsigned int nChild) const {
+bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
out.nDepth = nDepth + 1;
CKeyID id = key.GetPubKey().GetID();
memcpy(&out.vchFingerprint[0], &id, 4);
- out.nChild = nChild;
- return key.Derive(out.key, out.chaincode, nChild, chaincode);
+ out.nChild = _nChild;
+ return key.Derive(out.key, out.chaincode, _nChild, chaincode);
}
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'};
- unsigned char out[64];
- LockObject(out);
- CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(out);
- key.Set(&out[0], &out[32], true);
- memcpy(chaincode.begin(), &out[32], 32);
- UnlockObject(out);
+ 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);
nDepth = 0;
nChild = 0;
memset(vchFingerprint, 0, sizeof(vchFingerprint));
@@ -308,12 +296,10 @@ void ECC_Start() {
{
// Pass in a random blinding seed to the secp256k1 context.
- unsigned char seed[32];
- LockObject(seed);
- GetRandBytes(seed, 32);
- bool ret = secp256k1_context_randomize(ctx, seed);
+ std::vector<unsigned char, secure_allocator<unsigned char>> vseed(32);
+ GetRandBytes(vseed.data(), 32);
+ bool ret = secp256k1_context_randomize(ctx, vseed.data());
assert(ret);
- UnlockObject(seed);
}
secp256k1_context_sign = ctx;
diff --git a/src/key.h b/src/key.h
index b4f48d59f5..2c6f151727 100644
--- a/src/key.h
+++ b/src/key.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -15,7 +15,7 @@
#include <vector>
-/**
+/**
* secp256k1:
* const unsigned int PRIVATE_KEY_SIZE = 279;
* const unsigned int PUBLIC_KEY_SIZE = 65;
@@ -43,47 +43,39 @@ private:
bool fCompressed;
//! The actual byte data
- unsigned char vch[32];
+ 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:
//! Construct an invalid private key.
CKey() : fValid(false), fCompressed(false)
{
- LockObject(vch);
- }
-
- //! Copy constructor. This is necessary because of memlocking.
- CKey(const CKey& secret) : fValid(secret.fValid), fCompressed(secret.fCompressed)
- {
- LockObject(vch);
- memcpy(vch, secret.vch, sizeof(vch));
+ // Important: vch must be 32 bytes in length to not break serialization
+ keydata.resize(32);
}
//! Destructor (again necessary because of memlocking).
~CKey()
{
- UnlockObject(vch);
}
friend bool operator==(const CKey& a, const CKey& b)
{
- return a.fCompressed == b.fCompressed && a.size() == b.size() &&
- memcmp(&a.vch[0], &b.vch[0], a.size()) == 0;
+ return a.fCompressed == b.fCompressed &&
+ a.size() == b.size() &&
+ memcmp(a.keydata.data(), b.keydata.data(), a.size()) == 0;
}
//! Initialize using begin and end iterators to byte data.
template <typename T>
void Set(const T pbegin, const T pend, bool fCompressedIn)
{
- if (pend - pbegin != 32) {
+ if (size_t(pend - pbegin) != keydata.size()) {
fValid = false;
- return;
- }
- if (Check(&pbegin[0])) {
- memcpy(vch, (unsigned char*)&pbegin[0], 32);
+ } else if (Check(&pbegin[0])) {
+ memcpy(keydata.data(), (unsigned char*)&pbegin[0], keydata.size());
fValid = true;
fCompressed = fCompressedIn;
} else {
@@ -92,9 +84,9 @@ public:
}
//! Simple read-only vector-like interface.
- unsigned int size() const { return (fValid ? 32 : 0); }
- const unsigned char* begin() const { return vch; }
- const unsigned char* end() const { return vch + size(); }
+ unsigned int size() const { return (fValid ? keydata.size() : 0); }
+ const unsigned char* begin() const { return keydata.data(); }
+ const unsigned char* end() const { return keydata.data() + size(); }
//! Check whether this private key is valid.
bool IsValid() const { return fValid; }
@@ -102,15 +94,12 @@ 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);
/**
* Convert the private key to a CPrivKey (serialized OpenSSL private key data).
- * This is expensive.
+ * This is expensive.
*/
CPrivKey GetPrivKey() const;
@@ -146,9 +135,6 @@ public:
//! Load private key and check that public key matches.
bool Load(CPrivKey& privkey, CPubKey& vchPubKey, bool fSkipCheck);
-
- //! Check whether an element of a signature (r or s) is valid.
- static bool CheckSignatureElement(const unsigned char* vch, int len, bool half);
};
struct CExtKey {
@@ -160,8 +146,11 @@ struct CExtKey {
friend bool operator==(const CExtKey& a, const CExtKey& b)
{
- return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild &&
- a.chaincode == b.chaincode && a.key == b.key;
+ return a.nDepth == b.nDepth &&
+ memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 &&
+ a.nChild == b.nChild &&
+ a.chaincode == b.chaincode &&
+ a.key == b.key;
}
void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;
@@ -170,7 +159,7 @@ struct CExtKey {
CExtPubKey Neuter() const;
void SetMaster(const unsigned char* seed, unsigned int nSeedLen);
template <typename Stream>
- void Serialize(Stream& s, int nType, int nVersion) const
+ void Serialize(Stream& s) const
{
unsigned int len = BIP32_EXTKEY_SIZE;
::WriteCompactSize(s, len);
@@ -179,7 +168,7 @@ struct CExtKey {
s.write((const char *)&code[0], len);
}
template <typename Stream>
- void Unserialize(Stream& s, int nType, int nVersion)
+ void Unserialize(Stream& s)
{
unsigned int len = ::ReadCompactSize(s);
unsigned char code[BIP32_EXTKEY_SIZE];
diff --git a/src/keystore.cpp b/src/keystore.cpp
index d568a74350..b17567e99b 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
diff --git a/src/leveldb/.travis.yml b/src/leveldb/.travis.yml
new file mode 100644
index 0000000000..f5bd74c454
--- /dev/null
+++ b/src/leveldb/.travis.yml
@@ -0,0 +1,13 @@
+language: cpp
+compiler:
+- clang
+- gcc
+os:
+- linux
+- osx
+sudo: false
+before_install:
+- echo $LANG
+- echo $LC_ALL
+script:
+- make -j 4 check
diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile
index 2bd2cadcdd..07a5a1ead6 100644
--- a/src/leveldb/Makefile
+++ b/src/leveldb/Makefile
@@ -20,208 +20,395 @@ $(shell CC="$(CC)" CXX="$(CXX)" TARGET_OS="$(TARGET_OS)" \
# this file is generated by the previous line to set build flags and sources
include build_config.mk
+TESTS = \
+ db/autocompact_test \
+ db/c_test \
+ db/corruption_test \
+ db/db_test \
+ db/dbformat_test \
+ db/fault_injection_test \
+ db/filename_test \
+ db/log_test \
+ db/recovery_test \
+ db/skiplist_test \
+ db/version_edit_test \
+ db/version_set_test \
+ db/write_batch_test \
+ helpers/memenv/memenv_test \
+ issues/issue178_test \
+ issues/issue200_test \
+ table/filter_block_test \
+ table/table_test \
+ util/arena_test \
+ util/bloom_test \
+ util/cache_test \
+ util/coding_test \
+ util/crc32c_test \
+ util/env_test \
+ util/hash_test
+
+UTILS = \
+ db/db_bench \
+ db/leveldbutil
+
+# Put the object files in a subdirectory, but the application at the top of the object dir.
+PROGNAMES := $(notdir $(TESTS) $(UTILS))
+
+# On Linux may need libkyotocabinet-dev for dependency.
+BENCHMARKS = \
+ doc/bench/db_bench_sqlite3 \
+ doc/bench/db_bench_tree_db
+
CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT)
CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT)
LDFLAGS += $(PLATFORM_LDFLAGS)
LIBS += $(PLATFORM_LIBS)
-LIBOBJECTS = $(SOURCES:.cc=.o)
-MEMENVOBJECTS = $(MEMENV_SOURCES:.cc=.o)
-
-TESTUTIL = ./util/testutil.o
-TESTHARNESS = ./util/testharness.o $(TESTUTIL)
+SIMULATOR_OUTDIR=out-ios-x86
+DEVICE_OUTDIR=out-ios-arm
-# Note: iOS should probably be using libtool, not ar.
ifeq ($(PLATFORM), IOS)
+# Note: iOS should probably be using libtool, not ar.
AR=xcrun ar
+SIMULATORSDK=$(shell xcrun -sdk iphonesimulator --show-sdk-path)
+DEVICESDK=$(shell xcrun -sdk iphoneos --show-sdk-path)
+DEVICE_CFLAGS = -isysroot "$(DEVICESDK)" -arch armv6 -arch armv7 -arch armv7s -arch arm64
+SIMULATOR_CFLAGS = -isysroot "$(SIMULATORSDK)" -arch i686 -arch x86_64
+STATIC_OUTDIR=out-ios-universal
+else
+STATIC_OUTDIR=out-static
+SHARED_OUTDIR=out-shared
+STATIC_PROGRAMS := $(addprefix $(STATIC_OUTDIR)/, $(PROGNAMES))
+SHARED_PROGRAMS := $(addprefix $(SHARED_OUTDIR)/, db_bench)
endif
-TESTS = \
- arena_test \
- autocompact_test \
- bloom_test \
- c_test \
- cache_test \
- coding_test \
- corruption_test \
- crc32c_test \
- db_test \
- dbformat_test \
- env_test \
- filename_test \
- filter_block_test \
- hash_test \
- issue178_test \
- issue200_test \
- log_test \
- memenv_test \
- skiplist_test \
- table_test \
- version_edit_test \
- version_set_test \
- write_batch_test
-
-PROGRAMS = db_bench leveldbutil $(TESTS)
-BENCHMARKS = db_bench_sqlite3 db_bench_tree_db
-
-LIBRARY = libleveldb.a
-MEMENVLIBRARY = libmemenv.a
+STATIC_LIBOBJECTS := $(addprefix $(STATIC_OUTDIR)/, $(SOURCES:.cc=.o))
+STATIC_MEMENVOBJECTS := $(addprefix $(STATIC_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o))
+
+DEVICE_LIBOBJECTS := $(addprefix $(DEVICE_OUTDIR)/, $(SOURCES:.cc=.o))
+DEVICE_MEMENVOBJECTS := $(addprefix $(DEVICE_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o))
+
+SIMULATOR_LIBOBJECTS := $(addprefix $(SIMULATOR_OUTDIR)/, $(SOURCES:.cc=.o))
+SIMULATOR_MEMENVOBJECTS := $(addprefix $(SIMULATOR_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o))
+
+SHARED_LIBOBJECTS := $(addprefix $(SHARED_OUTDIR)/, $(SOURCES:.cc=.o))
+SHARED_MEMENVOBJECTS := $(addprefix $(SHARED_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o))
+
+TESTUTIL := $(STATIC_OUTDIR)/util/testutil.o
+TESTHARNESS := $(STATIC_OUTDIR)/util/testharness.o $(TESTUTIL)
+
+STATIC_TESTOBJS := $(addprefix $(STATIC_OUTDIR)/, $(addsuffix .o, $(TESTS)))
+STATIC_UTILOBJS := $(addprefix $(STATIC_OUTDIR)/, $(addsuffix .o, $(UTILS)))
+STATIC_ALLOBJS := $(STATIC_LIBOBJECTS) $(STATIC_MEMENVOBJECTS) $(STATIC_TESTOBJS) $(STATIC_UTILOBJS) $(TESTHARNESS)
+DEVICE_ALLOBJS := $(DEVICE_LIBOBJECTS) $(DEVICE_MEMENVOBJECTS)
+SIMULATOR_ALLOBJS := $(SIMULATOR_LIBOBJECTS) $(SIMULATOR_MEMENVOBJECTS)
default: all
# Should we build shared libraries?
ifneq ($(PLATFORM_SHARED_EXT),)
+# Many leveldb test apps use non-exported API's. Only build a subset for testing.
+SHARED_ALLOBJS := $(SHARED_LIBOBJECTS) $(SHARED_MEMENVOBJECTS) $(TESTHARNESS)
+
ifneq ($(PLATFORM_SHARED_VERSIONED),true)
-SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
-SHARED2 = $(SHARED1)
-SHARED3 = $(SHARED1)
-SHARED = $(SHARED1)
+SHARED_LIB1 = libleveldb.$(PLATFORM_SHARED_EXT)
+SHARED_LIB2 = $(SHARED_LIB1)
+SHARED_LIB3 = $(SHARED_LIB1)
+SHARED_LIBS = $(SHARED_LIB1)
+SHARED_MEMENVLIB = $(SHARED_OUTDIR)/libmemenv.a
else
# Update db.h if you change these.
-SHARED_MAJOR = 1
-SHARED_MINOR = 18
-SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
-SHARED2 = $(SHARED1).$(SHARED_MAJOR)
-SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR)
-SHARED = $(SHARED1) $(SHARED2) $(SHARED3)
-$(SHARED1): $(SHARED3)
- ln -fs $(SHARED3) $(SHARED1)
-$(SHARED2): $(SHARED3)
- ln -fs $(SHARED3) $(SHARED2)
+SHARED_VERSION_MAJOR = 1
+SHARED_VERSION_MINOR = 19
+SHARED_LIB1 = libleveldb.$(PLATFORM_SHARED_EXT)
+SHARED_LIB2 = $(SHARED_LIB1).$(SHARED_VERSION_MAJOR)
+SHARED_LIB3 = $(SHARED_LIB1).$(SHARED_VERSION_MAJOR).$(SHARED_VERSION_MINOR)
+SHARED_LIBS = $(SHARED_OUTDIR)/$(SHARED_LIB1) $(SHARED_OUTDIR)/$(SHARED_LIB2) $(SHARED_OUTDIR)/$(SHARED_LIB3)
+$(SHARED_OUTDIR)/$(SHARED_LIB1): $(SHARED_OUTDIR)/$(SHARED_LIB3)
+ ln -fs $(SHARED_LIB3) $(SHARED_OUTDIR)/$(SHARED_LIB1)
+$(SHARED_OUTDIR)/$(SHARED_LIB2): $(SHARED_OUTDIR)/$(SHARED_LIB3)
+ ln -fs $(SHARED_LIB3) $(SHARED_OUTDIR)/$(SHARED_LIB2)
+SHARED_MEMENVLIB = $(SHARED_OUTDIR)/libmemenv.a
endif
-$(SHARED3):
- $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) -o $(SHARED3) $(LIBS)
+$(SHARED_OUTDIR)/$(SHARED_LIB3): $(SHARED_LIBOBJECTS)
+ $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED_LIB2) $(SHARED_LIBOBJECTS) -o $(SHARED_OUTDIR)/$(SHARED_LIB3) $(LIBS)
endif # PLATFORM_SHARED_EXT
-all: $(SHARED) $(LIBRARY)
+all: $(SHARED_LIBS) $(SHARED_PROGRAMS) $(STATIC_OUTDIR)/libleveldb.a $(STATIC_OUTDIR)/libmemenv.a $(STATIC_PROGRAMS)
-check: all $(PROGRAMS) $(TESTS)
- for t in $(TESTS); do echo "***** Running $$t"; ./$$t || exit 1; done
+check: $(STATIC_PROGRAMS)
+ for t in $(notdir $(TESTS)); do echo "***** Running $$t"; $(STATIC_OUTDIR)/$$t || exit 1; done
clean:
- -rm -f $(PROGRAMS) $(BENCHMARKS) $(LIBRARY) $(SHARED) $(MEMENVLIBRARY) */*.o */*/*.o ios-x86/*/*.o ios-arm/*/*.o build_config.mk
- -rm -rf ios-x86/* ios-arm/*
+ -rm -rf out-static out-shared out-ios-x86 out-ios-arm out-ios-universal
+ -rm -f build_config.mk
+ -rm -rf ios-x86 ios-arm
-$(LIBRARY): $(LIBOBJECTS)
- rm -f $@
- $(AR) -rs $@ $(LIBOBJECTS)
+$(STATIC_OUTDIR):
+ mkdir $@
-db_bench: db/db_bench.o $(LIBOBJECTS) $(TESTUTIL)
- $(CXX) $(LDFLAGS) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LIBS)
+$(STATIC_OUTDIR)/db: | $(STATIC_OUTDIR)
+ mkdir $@
-db_bench_sqlite3: doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL)
- $(CXX) $(LDFLAGS) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lsqlite3 $(LIBS)
+$(STATIC_OUTDIR)/helpers/memenv: | $(STATIC_OUTDIR)
+ mkdir -p $@
-db_bench_tree_db: doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL)
- $(CXX) $(LDFLAGS) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lkyotocabinet $(LIBS)
+$(STATIC_OUTDIR)/port: | $(STATIC_OUTDIR)
+ mkdir $@
-leveldbutil: db/leveldb_main.o $(LIBOBJECTS)
- $(CXX) $(LDFLAGS) db/leveldb_main.o $(LIBOBJECTS) -o $@ $(LIBS)
+$(STATIC_OUTDIR)/table: | $(STATIC_OUTDIR)
+ mkdir $@
-arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(STATIC_OUTDIR)/util: | $(STATIC_OUTDIR)
+ mkdir $@
-autocompact_test: db/autocompact_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/autocompact_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+.PHONY: STATIC_OBJDIRS
+STATIC_OBJDIRS: \
+ $(STATIC_OUTDIR)/db \
+ $(STATIC_OUTDIR)/port \
+ $(STATIC_OUTDIR)/table \
+ $(STATIC_OUTDIR)/util \
+ $(STATIC_OUTDIR)/helpers/memenv
-bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SHARED_OUTDIR):
+ mkdir $@
-c_test: db/c_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SHARED_OUTDIR)/db: | $(SHARED_OUTDIR)
+ mkdir $@
-cache_test: util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SHARED_OUTDIR)/helpers/memenv: | $(SHARED_OUTDIR)
+ mkdir -p $@
-coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SHARED_OUTDIR)/port: | $(SHARED_OUTDIR)
+ mkdir $@
-corruption_test: db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SHARED_OUTDIR)/table: | $(SHARED_OUTDIR)
+ mkdir $@
-crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SHARED_OUTDIR)/util: | $(SHARED_OUTDIR)
+ mkdir $@
-db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+.PHONY: SHARED_OBJDIRS
+SHARED_OBJDIRS: \
+ $(SHARED_OUTDIR)/db \
+ $(SHARED_OUTDIR)/port \
+ $(SHARED_OUTDIR)/table \
+ $(SHARED_OUTDIR)/util \
+ $(SHARED_OUTDIR)/helpers/memenv
-dbformat_test: db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(DEVICE_OUTDIR):
+ mkdir $@
-env_test: util/env_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(DEVICE_OUTDIR)/db: | $(DEVICE_OUTDIR)
+ mkdir $@
-filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(DEVICE_OUTDIR)/helpers/memenv: | $(DEVICE_OUTDIR)
+ mkdir -p $@
-filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(DEVICE_OUTDIR)/port: | $(DEVICE_OUTDIR)
+ mkdir $@
-hash_test: util/hash_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) util/hash_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(DEVICE_OUTDIR)/table: | $(DEVICE_OUTDIR)
+ mkdir $@
-issue178_test: issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(DEVICE_OUTDIR)/util: | $(DEVICE_OUTDIR)
+ mkdir $@
-issue200_test: issues/issue200_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) issues/issue200_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+.PHONY: DEVICE_OBJDIRS
+DEVICE_OBJDIRS: \
+ $(DEVICE_OUTDIR)/db \
+ $(DEVICE_OUTDIR)/port \
+ $(DEVICE_OUTDIR)/table \
+ $(DEVICE_OUTDIR)/util \
+ $(DEVICE_OUTDIR)/helpers/memenv
-log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SIMULATOR_OUTDIR):
+ mkdir $@
-table_test: table/table_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SIMULATOR_OUTDIR)/db: | $(SIMULATOR_OUTDIR)
+ mkdir $@
-skiplist_test: db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SIMULATOR_OUTDIR)/helpers/memenv: | $(SIMULATOR_OUTDIR)
+ mkdir -p $@
-version_edit_test: db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SIMULATOR_OUTDIR)/port: | $(SIMULATOR_OUTDIR)
+ mkdir $@
-version_set_test: db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SIMULATOR_OUTDIR)/table: | $(SIMULATOR_OUTDIR)
+ mkdir $@
-write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(SIMULATOR_OUTDIR)/util: | $(SIMULATOR_OUTDIR)
+ mkdir $@
-$(MEMENVLIBRARY) : $(MEMENVOBJECTS)
- rm -f $@
- $(AR) -rs $@ $(MEMENVOBJECTS)
+.PHONY: SIMULATOR_OBJDIRS
+SIMULATOR_OBJDIRS: \
+ $(SIMULATOR_OUTDIR)/db \
+ $(SIMULATOR_OUTDIR)/port \
+ $(SIMULATOR_OUTDIR)/table \
+ $(SIMULATOR_OUTDIR)/util \
+ $(SIMULATOR_OUTDIR)/helpers/memenv
-memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS)
- $(CXX) $(LDFLAGS) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LIBS)
+$(STATIC_ALLOBJS): | STATIC_OBJDIRS
+$(DEVICE_ALLOBJS): | DEVICE_OBJDIRS
+$(SIMULATOR_ALLOBJS): | SIMULATOR_OBJDIRS
+$(SHARED_ALLOBJS): | SHARED_OBJDIRS
ifeq ($(PLATFORM), IOS)
-# For iOS, create universal object files to be used on both the simulator and
+$(DEVICE_OUTDIR)/libleveldb.a: $(DEVICE_LIBOBJECTS)
+ rm -f $@
+ $(AR) -rs $@ $(DEVICE_LIBOBJECTS)
+
+$(SIMULATOR_OUTDIR)/libleveldb.a: $(SIMULATOR_LIBOBJECTS)
+ rm -f $@
+ $(AR) -rs $@ $(SIMULATOR_LIBOBJECTS)
+
+$(DEVICE_OUTDIR)/libmemenv.a: $(DEVICE_MEMENVOBJECTS)
+ rm -f $@
+ $(AR) -rs $@ $(DEVICE_MEMENVOBJECTS)
+
+$(SIMULATOR_OUTDIR)/libmemenv.a: $(SIMULATOR_MEMENVOBJECTS)
+ rm -f $@
+ $(AR) -rs $@ $(SIMULATOR_MEMENVOBJECTS)
+
+# For iOS, create universal object libraries to be used on both the simulator and
# a device.
-PLATFORMSROOT=/Applications/Xcode.app/Contents/Developer/Platforms
-SIMULATORROOT=$(PLATFORMSROOT)/iPhoneSimulator.platform/Developer
-DEVICEROOT=$(PLATFORMSROOT)/iPhoneOS.platform/Developer
-IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBundleShortVersionString)
-IOSARCH=-arch armv6 -arch armv7 -arch armv7s -arch arm64
-
-.cc.o:
- mkdir -p ios-x86/$(dir $@)
- xcrun -sdk iphonesimulator $(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@
- mkdir -p ios-arm/$(dir $@)
- xcrun -sdk iphoneos $(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk $(IOSARCH) -c $< -o ios-arm/$@
- xcrun lipo ios-x86/$@ ios-arm/$@ -create -output $@
-
-.c.o:
- mkdir -p ios-x86/$(dir $@)
- xcrun -sdk iphonesimulator $(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@
- mkdir -p ios-arm/$(dir $@)
- xcrun -sdk iphoneos $(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk $(IOSARCH) -c $< -o ios-arm/$@
- xcrun lipo ios-x86/$@ ios-arm/$@ -create -output $@
+$(STATIC_OUTDIR)/libleveldb.a: $(STATIC_OUTDIR) $(DEVICE_OUTDIR)/libleveldb.a $(SIMULATOR_OUTDIR)/libleveldb.a
+ lipo -create $(DEVICE_OUTDIR)/libleveldb.a $(SIMULATOR_OUTDIR)/libleveldb.a -output $@
+$(STATIC_OUTDIR)/libmemenv.a: $(STATIC_OUTDIR) $(DEVICE_OUTDIR)/libmemenv.a $(SIMULATOR_OUTDIR)/libmemenv.a
+ lipo -create $(DEVICE_OUTDIR)/libmemenv.a $(SIMULATOR_OUTDIR)/libmemenv.a -output $@
else
-.cc.o:
+$(STATIC_OUTDIR)/libleveldb.a:$(STATIC_LIBOBJECTS)
+ rm -f $@
+ $(AR) -rs $@ $(STATIC_LIBOBJECTS)
+
+$(STATIC_OUTDIR)/libmemenv.a:$(STATIC_MEMENVOBJECTS)
+ rm -f $@
+ $(AR) -rs $@ $(STATIC_MEMENVOBJECTS)
+endif
+
+$(SHARED_MEMENVLIB):$(SHARED_MEMENVOBJECTS)
+ rm -f $@
+ $(AR) -rs $@ $(SHARED_MEMENVOBJECTS)
+
+$(STATIC_OUTDIR)/db_bench:db/db_bench.cc $(STATIC_LIBOBJECTS) $(TESTUTIL)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/db_bench.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/db_bench_sqlite3:doc/bench/db_bench_sqlite3.cc $(STATIC_LIBOBJECTS) $(TESTUTIL)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) doc/bench/db_bench_sqlite3.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) -o $@ -lsqlite3 $(LIBS)
+
+$(STATIC_OUTDIR)/db_bench_tree_db:doc/bench/db_bench_tree_db.cc $(STATIC_LIBOBJECTS) $(TESTUTIL)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) doc/bench/db_bench_tree_db.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) -o $@ -lkyotocabinet $(LIBS)
+
+$(STATIC_OUTDIR)/leveldbutil:db/leveldbutil.cc $(STATIC_LIBOBJECTS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/leveldbutil.cc $(STATIC_LIBOBJECTS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/arena_test:util/arena_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) util/arena_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/autocompact_test:db/autocompact_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/autocompact_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/bloom_test:util/bloom_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) util/bloom_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/c_test:$(STATIC_OUTDIR)/db/c_test.o $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(STATIC_OUTDIR)/db/c_test.o $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/cache_test:util/cache_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) util/cache_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/coding_test:util/coding_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) util/coding_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/corruption_test:db/corruption_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/corruption_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/crc32c_test:util/crc32c_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) util/crc32c_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/db_test:db/db_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/db_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(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_test:util/env_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) util/env_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/fault_injection_test:db/fault_injection_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/fault_injection_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/filename_test:db/filename_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/filename_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/filter_block_test:table/filter_block_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) table/filter_block_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/hash_test:util/hash_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) util/hash_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/issue178_test:issues/issue178_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) issues/issue178_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/issue200_test:issues/issue200_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) issues/issue200_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/log_test:db/log_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/log_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/recovery_test:db/recovery_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/recovery_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/table_test:table/table_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) table/table_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/skiplist_test:db/skiplist_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/skiplist_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/version_edit_test:db/version_edit_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/version_edit_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/version_set_test:db/version_set_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/version_set_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/write_batch_test:db/write_batch_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) db/write_batch_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
+$(STATIC_OUTDIR)/memenv_test:$(STATIC_OUTDIR)/helpers/memenv/memenv_test.o $(STATIC_OUTDIR)/libmemenv.a $(STATIC_OUTDIR)/libleveldb.a $(TESTHARNESS)
+ $(XCRUN) $(CXX) $(LDFLAGS) $(STATIC_OUTDIR)/helpers/memenv/memenv_test.o $(STATIC_OUTDIR)/libmemenv.a $(STATIC_OUTDIR)/libleveldb.a $(TESTHARNESS) -o $@ $(LIBS)
+
+$(SHARED_OUTDIR)/db_bench:$(SHARED_OUTDIR)/db/db_bench.o $(SHARED_LIBS) $(TESTUTIL)
+ $(XCRUN) $(CXX) $(LDFLAGS) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SHARED_OUTDIR)/db/db_bench.o $(TESTUTIL) $(SHARED_OUTDIR)/$(SHARED_LIB3) -o $@ $(LIBS)
+
+.PHONY: run-shared
+run-shared: $(SHARED_OUTDIR)/db_bench
+ LD_LIBRARY_PATH=$(SHARED_OUTDIR) $(SHARED_OUTDIR)/db_bench
+
+$(SIMULATOR_OUTDIR)/%.o: %.cc
+ xcrun -sdk iphonesimulator $(CXX) $(CXXFLAGS) $(SIMULATOR_CFLAGS) -c $< -o $@
+
+$(DEVICE_OUTDIR)/%.o: %.cc
+ xcrun -sdk iphoneos $(CXX) $(CXXFLAGS) $(DEVICE_CFLAGS) -c $< -o $@
+
+$(SIMULATOR_OUTDIR)/%.o: %.c
+ xcrun -sdk iphonesimulator $(CC) $(CFLAGS) $(SIMULATOR_CFLAGS) -c $< -o $@
+
+$(DEVICE_OUTDIR)/%.o: %.c
+ xcrun -sdk iphoneos $(CC) $(CFLAGS) $(DEVICE_CFLAGS) -c $< -o $@
+
+$(STATIC_OUTDIR)/%.o: %.cc
$(CXX) $(CXXFLAGS) -c $< -o $@
-.c.o:
+$(STATIC_OUTDIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
-endif
+
+$(SHARED_OUTDIR)/%.o: %.cc
+ $(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) -c $< -o $@
+
+$(SHARED_OUTDIR)/%.o: %.c
+ $(CC) $(CFLAGS) $(PLATFORM_SHARED_CFLAGS) -c $< -o $@
diff --git a/src/leveldb/README b/src/leveldb/README
deleted file mode 100644
index 3618adeeed..0000000000
--- a/src/leveldb/README
+++ /dev/null
@@ -1,51 +0,0 @@
-leveldb: A key-value store
-Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)
-
-The code under this directory implements a system for maintaining a
-persistent key/value store.
-
-See doc/index.html for more explanation.
-See doc/impl.html 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
-internal APIs may be changed without warning.
-
-Guide to header files:
-
-include/db.h
- Main interface to the DB: Start here
-
-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. 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.)
-
-include/iterator.h
- Interface for iterating over data. You can get an iterator
- from a DB object.
-
-include/write_batch.h
- Interface for atomically applying multiple updates to a database.
-
-include/slice.h
- A simple module for maintaining a pointer and a 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
- Abstraction of the OS environment. A posix implementation of
- this interface is in util/env_posix.cc
-
-include/table.h
-include/table_builder.h
- Lower-level modules that most clients probably won't use directly
diff --git a/src/leveldb/README.md b/src/leveldb/README.md
index 480affb5ca..c75b185e0e 100644
--- a/src/leveldb/README.md
+++ b/src/leveldb/README.md
@@ -1,5 +1,7 @@
**LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.**
+[![Build Status](https://travis-ci.org/google/leveldb.svg?branch=master)](https://travis-ci.org/google/leveldb)
+
Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)
# Features
@@ -10,9 +12,11 @@ Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)
* Multiple changes can be made in one atomic batch.
* Users can create a transient snapshot to get a consistent view of data.
* Forward and backward iteration is supported over the data.
- * Data is automatically compressed using the [Snappy compression library](http://code.google.com/p/snappy).
+ * Data is automatically compressed using the [Snappy compression library](http://google.github.io/snappy/).
* External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions.
- * [Detailed documentation](http://htmlpreview.github.io/?https://github.com/google/leveldb/blob/master/doc/index.html) about how to use the library is included with the source code.
+
+# Documentation
+ [LevelDB library documentation](https://rawgit.com/google/leveldb/master/doc/index.html) is online and bundled with the source code.
# Limitations
@@ -20,6 +24,37 @@ Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)
* Only a single process (possibly multi-threaded) can access a particular database at a time.
* There is no client-server support builtin to the library. An application that needs such support will have to wrap their own server around the library.
+# Contributing to the leveldb Project
+The leveldb project welcomes contributions. leveldb's primary goal is to be
+a reliable and fast key/value store. Changes that are in line with the
+features/limitations outlined above, and meet the requirements below,
+will be considered.
+
+Contribution requirements:
+
+1. **POSIX only**. We _generally_ will only accept changes that are both
+ compiled, and tested on a POSIX platform - usually Linux. Very small
+ changes will sometimes be accepted, but consider that more of an
+ exception than the rule.
+
+2. **Stable API**. We strive very hard to maintain a stable API. Changes that
+ require changes for projects using leveldb _might_ be rejected without
+ sufficient benefit to the project.
+
+3. **Tests**: All changes must be accompanied by a new (or changed) test, or
+ a sufficient explanation as to why a new (or changed) test is not required.
+
+## Submitting a Pull Request
+Before any pull request will be accepted the author must first sign a
+Contributor License Agreement (CLA) at https://cla.developers.google.com/.
+
+In order to keep the commit timeline linear
+[squash](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Squashing-Commits)
+your changes down to a single commit and [rebase](https://git-scm.com/docs/git-rebase)
+on google/leveldb/master. This keeps the commit timeline linear and more easily sync'ed
+with the internal repository at Google. More information at GitHub's
+[About Git rebase](https://help.github.com/articles/about-git-rebase/) page.
+
# Performance
Here is a performance report (with explanations) from the run of the
diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform
index a1101c1bda..d7edab1d87 100755
--- a/src/leveldb/build_detect_platform
+++ b/src/leveldb/build_detect_platform
@@ -175,7 +175,7 @@ DIRS="$PREFIX/db $PREFIX/util $PREFIX/table"
set -f # temporarily disable globbing so that our patterns aren't expanded
PRUNE_TEST="-name *test*.cc -prune"
PRUNE_BENCH="-name *_bench.cc -prune"
-PRUNE_TOOL="-name leveldb_main.cc -prune"
+PRUNE_TOOL="-name leveldbutil.cc -prune"
PORTABLE_FILES=`find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o $PRUNE_TOOL -o -name '*.cc' -print | sort | sed "s,^$PREFIX/,," | tr "\n" " "`
set +f # re-enable globbing
diff --git a/src/leveldb/db/corruption_test.cc b/src/leveldb/db/corruption_test.cc
index 96afc68913..37a484d25f 100644
--- a/src/leveldb/db/corruption_test.cc
+++ b/src/leveldb/db/corruption_test.cc
@@ -36,7 +36,7 @@ class CorruptionTest {
tiny_cache_ = NewLRUCache(100);
options_.env = &env_;
options_.block_cache = tiny_cache_;
- dbname_ = test::TmpDir() + "/db_test";
+ dbname_ = test::TmpDir() + "/corruption_test";
DestroyDB(dbname_, options_);
db_ = NULL;
diff --git a/src/leveldb/db/db_bench.cc b/src/leveldb/db/db_bench.cc
index 705a170aae..7a0f5e08cd 100644
--- a/src/leveldb/db/db_bench.cc
+++ b/src/leveldb/db/db_bench.cc
@@ -33,6 +33,7 @@
// readmissing -- read N missing keys in random order
// readhot -- read N times in random order from 1% section of DB
// seekrandom -- N random seeks
+// open -- cost of opening a DB
// crc32c -- repeated crc32c of 4K of data
// acquireload -- load N*1000 times
// Meta operations:
@@ -99,6 +100,9 @@ static int FLAGS_bloom_bits = -1;
// benchmark will fail.
static bool FLAGS_use_existing_db = false;
+// If true, reuse existing log/MANIFEST files when re-opening a database.
+static bool FLAGS_reuse_logs = false;
+
// Use the db with the following name.
static const char* FLAGS_db = NULL;
@@ -138,6 +142,7 @@ class RandomGenerator {
}
};
+#if defined(__linux)
static Slice TrimSpace(Slice s) {
size_t start = 0;
while (start < s.size() && isspace(s[start])) {
@@ -149,6 +154,7 @@ static Slice TrimSpace(Slice s) {
}
return Slice(s.data() + start, limit - start);
}
+#endif
static void AppendWithSpace(std::string* str, Slice msg) {
if (msg.empty()) return;
@@ -442,7 +448,11 @@ class Benchmark {
bool fresh_db = false;
int num_threads = FLAGS_threads;
- if (name == Slice("fillseq")) {
+ if (name == Slice("open")) {
+ method = &Benchmark::OpenBench;
+ num_ /= 10000;
+ if (num_ < 1) num_ = 1;
+ } else if (name == Slice("fillseq")) {
fresh_db = true;
method = &Benchmark::WriteSeq;
} else if (name == Slice("fillbatch")) {
@@ -695,6 +705,7 @@ class Benchmark {
options.write_buffer_size = FLAGS_write_buffer_size;
options.max_open_files = FLAGS_open_files;
options.filter_policy = filter_policy_;
+ options.reuse_logs = FLAGS_reuse_logs;
Status s = DB::Open(options, FLAGS_db, &db_);
if (!s.ok()) {
fprintf(stderr, "open error: %s\n", s.ToString().c_str());
@@ -702,6 +713,14 @@ class Benchmark {
}
}
+ void OpenBench(ThreadState* thread) {
+ for (int i = 0; i < num_; i++) {
+ delete db_;
+ Open();
+ thread->stats.FinishedSingleOp();
+ }
+ }
+
void WriteSeq(ThreadState* thread) {
DoWrite(thread, true);
}
@@ -941,6 +960,9 @@ int main(int argc, char** argv) {
} else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_use_existing_db = n;
+ } else if (sscanf(argv[i], "--reuse_logs=%d%c", &n, &junk) == 1 &&
+ (n == 0 || n == 1)) {
+ FLAGS_reuse_logs = n;
} else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) {
FLAGS_num = n;
} else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) {
diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc
index 49b95953b4..60f4e66e55 100644
--- a/src/leveldb/db/db_impl.cc
+++ b/src/leveldb/db/db_impl.cc
@@ -125,7 +125,7 @@ DBImpl::DBImpl(const Options& raw_options, const std::string& dbname)
db_lock_(NULL),
shutting_down_(NULL),
bg_cv_(&mutex_),
- mem_(new MemTable(internal_comparator_)),
+ mem_(NULL),
imm_(NULL),
logfile_(NULL),
logfile_number_(0),
@@ -134,7 +134,6 @@ DBImpl::DBImpl(const Options& raw_options, const std::string& dbname)
tmp_batch_(new WriteBatch),
bg_compaction_scheduled_(false),
manual_compaction_(NULL) {
- mem_->Ref();
has_imm_.Release_Store(NULL);
// Reserve ten files or so for other uses and give the rest to TableCache.
@@ -271,7 +270,7 @@ void DBImpl::DeleteObsoleteFiles() {
}
}
-Status DBImpl::Recover(VersionEdit* edit) {
+Status DBImpl::Recover(VersionEdit* edit, bool *save_manifest) {
mutex_.AssertHeld();
// Ignore error from CreateDir since the creation of the DB is
@@ -301,66 +300,69 @@ Status DBImpl::Recover(VersionEdit* edit) {
}
}
- s = versions_->Recover();
- if (s.ok()) {
- SequenceNumber max_sequence(0);
-
- // Recover from all newer log files than the ones named in the
- // descriptor (new log files may have been added by the previous
- // incarnation without registering them in the descriptor).
- //
- // Note that PrevLogNumber() is no longer used, but we pay
- // attention to it in case we are recovering a database
- // produced by an older version of leveldb.
- const uint64_t min_log = versions_->LogNumber();
- const uint64_t prev_log = versions_->PrevLogNumber();
- std::vector<std::string> filenames;
- s = env_->GetChildren(dbname_, &filenames);
+ s = versions_->Recover(save_manifest);
+ if (!s.ok()) {
+ return s;
+ }
+ SequenceNumber max_sequence(0);
+
+ // Recover from all newer log files than the ones named in the
+ // descriptor (new log files may have been added by the previous
+ // incarnation without registering them in the descriptor).
+ //
+ // Note that PrevLogNumber() is no longer used, but we pay
+ // attention to it in case we are recovering a database
+ // produced by an older version of leveldb.
+ const uint64_t min_log = versions_->LogNumber();
+ const uint64_t prev_log = versions_->PrevLogNumber();
+ std::vector<std::string> filenames;
+ s = env_->GetChildren(dbname_, &filenames);
+ if (!s.ok()) {
+ return s;
+ }
+ std::set<uint64_t> expected;
+ versions_->AddLiveFiles(&expected);
+ uint64_t number;
+ FileType type;
+ std::vector<uint64_t> logs;
+ for (size_t i = 0; i < filenames.size(); i++) {
+ if (ParseFileName(filenames[i], &number, &type)) {
+ expected.erase(number);
+ if (type == kLogFile && ((number >= min_log) || (number == prev_log)))
+ logs.push_back(number);
+ }
+ }
+ if (!expected.empty()) {
+ char buf[50];
+ snprintf(buf, sizeof(buf), "%d missing files; e.g.",
+ static_cast<int>(expected.size()));
+ return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin())));
+ }
+
+ // Recover in the order in which the logs were generated
+ std::sort(logs.begin(), logs.end());
+ for (size_t i = 0; i < logs.size(); i++) {
+ s = RecoverLogFile(logs[i], (i == logs.size() - 1), save_manifest, edit,
+ &max_sequence);
if (!s.ok()) {
return s;
}
- std::set<uint64_t> expected;
- versions_->AddLiveFiles(&expected);
- uint64_t number;
- FileType type;
- std::vector<uint64_t> logs;
- for (size_t i = 0; i < filenames.size(); i++) {
- if (ParseFileName(filenames[i], &number, &type)) {
- expected.erase(number);
- if (type == kLogFile && ((number >= min_log) || (number == prev_log)))
- logs.push_back(number);
- }
- }
- if (!expected.empty()) {
- char buf[50];
- snprintf(buf, sizeof(buf), "%d missing files; e.g.",
- static_cast<int>(expected.size()));
- return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin())));
- }
-
- // Recover in the order in which the logs were generated
- std::sort(logs.begin(), logs.end());
- for (size_t i = 0; i < logs.size(); i++) {
- s = RecoverLogFile(logs[i], edit, &max_sequence);
- // The previous incarnation may not have written any MANIFEST
- // records after allocating this log number. So we manually
- // update the file number allocation counter in VersionSet.
- versions_->MarkFileNumberUsed(logs[i]);
- }
+ // The previous incarnation may not have written any MANIFEST
+ // records after allocating this log number. So we manually
+ // update the file number allocation counter in VersionSet.
+ versions_->MarkFileNumberUsed(logs[i]);
+ }
- if (s.ok()) {
- if (versions_->LastSequence() < max_sequence) {
- versions_->SetLastSequence(max_sequence);
- }
- }
+ if (versions_->LastSequence() < max_sequence) {
+ versions_->SetLastSequence(max_sequence);
}
- return s;
+ return Status::OK();
}
-Status DBImpl::RecoverLogFile(uint64_t log_number,
- VersionEdit* edit,
+Status DBImpl::RecoverLogFile(uint64_t log_number, bool last_log,
+ bool* save_manifest, VersionEdit* edit,
SequenceNumber* max_sequence) {
struct LogReporter : public log::Reader::Reporter {
Env* env;
@@ -405,6 +407,7 @@ Status DBImpl::RecoverLogFile(uint64_t log_number,
std::string scratch;
Slice record;
WriteBatch batch;
+ int compactions = 0;
MemTable* mem = NULL;
while (reader.ReadRecord(&record, &scratch) &&
status.ok()) {
@@ -432,25 +435,52 @@ Status DBImpl::RecoverLogFile(uint64_t log_number,
}
if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) {
+ compactions++;
+ *save_manifest = true;
status = WriteLevel0Table(mem, edit, NULL);
+ mem->Unref();
+ mem = NULL;
if (!status.ok()) {
// Reflect errors immediately so that conditions like full
// file-systems cause the DB::Open() to fail.
break;
}
- mem->Unref();
- mem = NULL;
}
}
- if (status.ok() && mem != NULL) {
- status = WriteLevel0Table(mem, edit, NULL);
- // Reflect errors immediately so that conditions like full
- // file-systems cause the DB::Open() to fail.
+ delete file;
+
+ // See if we should keep reusing the last log file.
+ if (status.ok() && options_.reuse_logs && last_log && compactions == 0) {
+ assert(logfile_ == NULL);
+ assert(log_ == NULL);
+ assert(mem_ == NULL);
+ uint64_t lfile_size;
+ if (env_->GetFileSize(fname, &lfile_size).ok() &&
+ env_->NewAppendableFile(fname, &logfile_).ok()) {
+ Log(options_.info_log, "Reusing old log %s \n", fname.c_str());
+ log_ = new log::Writer(logfile_, lfile_size);
+ logfile_number_ = log_number;
+ if (mem != NULL) {
+ mem_ = mem;
+ mem = NULL;
+ } else {
+ // mem can be NULL if lognum exists but was empty.
+ mem_ = new MemTable(internal_comparator_);
+ mem_->Ref();
+ }
+ }
+ }
+
+ if (mem != NULL) {
+ // mem did not get reused; compact it.
+ if (status.ok()) {
+ *save_manifest = true;
+ status = WriteLevel0Table(mem, edit, NULL);
+ }
+ mem->Unref();
}
- if (mem != NULL) mem->Unref();
- delete file;
return status;
}
@@ -821,8 +851,9 @@ Status DBImpl::FinishCompactionOutputFile(CompactionState* compact,
delete iter;
if (s.ok()) {
Log(options_.info_log,
- "Generated table #%llu: %lld keys, %lld bytes",
+ "Generated table #%llu@%d: %lld keys, %lld bytes",
(unsigned long long) output_number,
+ compact->compaction->level(),
(unsigned long long) current_entries,
(unsigned long long) current_bytes);
}
@@ -1395,6 +1426,19 @@ bool DBImpl::GetProperty(const Slice& property, std::string* value) {
} else if (in == "sstables") {
*value = versions_->current()->DebugString();
return true;
+ } else if (in == "approximate-memory-usage") {
+ size_t total_usage = options_.block_cache->TotalCharge();
+ if (mem_) {
+ total_usage += mem_->ApproximateMemoryUsage();
+ }
+ if (imm_) {
+ total_usage += imm_->ApproximateMemoryUsage();
+ }
+ char buf[50];
+ snprintf(buf, sizeof(buf), "%llu",
+ static_cast<unsigned long long>(total_usage));
+ value->append(buf);
+ return true;
}
return false;
@@ -1449,8 +1493,11 @@ Status DB::Open(const Options& options, const std::string& dbname,
DBImpl* impl = new DBImpl(options, dbname);
impl->mutex_.Lock();
VersionEdit edit;
- Status s = impl->Recover(&edit); // Handles create_if_missing, error_if_exists
- if (s.ok()) {
+ // Recover handles create_if_missing, error_if_exists
+ bool save_manifest = false;
+ Status s = impl->Recover(&edit, &save_manifest);
+ if (s.ok() && impl->mem_ == NULL) {
+ // Create new log and a corresponding memtable.
uint64_t new_log_number = impl->versions_->NewFileNumber();
WritableFile* lfile;
s = options.env->NewWritableFile(LogFileName(dbname, new_log_number),
@@ -1460,15 +1507,22 @@ Status DB::Open(const Options& options, const std::string& dbname,
impl->logfile_ = lfile;
impl->logfile_number_ = new_log_number;
impl->log_ = new log::Writer(lfile);
- s = impl->versions_->LogAndApply(&edit, &impl->mutex_);
- }
- if (s.ok()) {
- impl->DeleteObsoleteFiles();
- impl->MaybeScheduleCompaction();
+ impl->mem_ = new MemTable(impl->internal_comparator_);
+ impl->mem_->Ref();
}
}
+ if (s.ok() && save_manifest) {
+ edit.SetPrevLogNumber(0); // No older logs needed after recovery.
+ edit.SetLogNumber(impl->logfile_number_);
+ s = impl->versions_->LogAndApply(&edit, &impl->mutex_);
+ }
+ if (s.ok()) {
+ impl->DeleteObsoleteFiles();
+ impl->MaybeScheduleCompaction();
+ }
impl->mutex_.Unlock();
if (s.ok()) {
+ assert(impl->mem_ != NULL);
*dbptr = impl;
} else {
delete impl;
diff --git a/src/leveldb/db/db_impl.h b/src/leveldb/db/db_impl.h
index cfc998164a..8ff323e728 100644
--- a/src/leveldb/db/db_impl.h
+++ b/src/leveldb/db/db_impl.h
@@ -78,7 +78,8 @@ class DBImpl : public DB {
// Recover the descriptor from persistent storage. May do a significant
// amount of work to recover recently logged updates. Any changes to
// be made to the descriptor are added to *edit.
- Status Recover(VersionEdit* edit) EXCLUSIVE_LOCKS_REQUIRED(mutex_);
+ Status Recover(VersionEdit* edit, bool* save_manifest)
+ EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void MaybeIgnoreError(Status* s) const;
@@ -90,9 +91,8 @@ class DBImpl : public DB {
// Errors are recorded in bg_error_.
void CompactMemTable() EXCLUSIVE_LOCKS_REQUIRED(mutex_);
- Status RecoverLogFile(uint64_t log_number,
- VersionEdit* edit,
- SequenceNumber* max_sequence)
+ Status RecoverLogFile(uint64_t log_number, bool last_log, bool* save_manifest,
+ VersionEdit* edit, SequenceNumber* max_sequence)
EXCLUSIVE_LOCKS_REQUIRED(mutex_);
Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base)
diff --git a/src/leveldb/db/db_test.cc b/src/leveldb/db/db_test.cc
index 0fed9137d5..a0b08bc19c 100644
--- a/src/leveldb/db/db_test.cc
+++ b/src/leveldb/db/db_test.cc
@@ -193,6 +193,7 @@ class DBTest {
// Sequence of option configurations to try
enum OptionConfig {
kDefault,
+ kReuse,
kFilter,
kUncompressed,
kEnd
@@ -237,7 +238,11 @@ class DBTest {
// Return the current option configuration.
Options CurrentOptions() {
Options options;
+ options.reuse_logs = false;
switch (option_config_) {
+ case kReuse:
+ options.reuse_logs = true;
+ break;
case kFilter:
options.filter_policy = filter_policy_;
break;
@@ -558,6 +563,17 @@ TEST(DBTest, GetFromVersions) {
} while (ChangeOptions());
}
+TEST(DBTest, GetMemUsage) {
+ do {
+ ASSERT_OK(Put("foo", "v1"));
+ std::string val;
+ ASSERT_TRUE(db_->GetProperty("leveldb.approximate-memory-usage", &val));
+ int mem_usage = atoi(val.c_str());
+ ASSERT_GT(mem_usage, 0);
+ ASSERT_LT(mem_usage, 5*1024*1024);
+ } while (ChangeOptions());
+}
+
TEST(DBTest, GetSnapshot) {
do {
// Try with both a short key and a long key
@@ -1080,6 +1096,14 @@ TEST(DBTest, ApproximateSizes) {
// 0 because GetApproximateSizes() does not account for memtable space
ASSERT_TRUE(Between(Size("", Key(50)), 0, 0));
+ if (options.reuse_logs) {
+ // Recovery will reuse memtable, and GetApproximateSizes() does not
+ // account for memtable usage;
+ Reopen(&options);
+ ASSERT_TRUE(Between(Size("", Key(50)), 0, 0));
+ continue;
+ }
+
// Check sizes across recovery by reopening a few times
for (int run = 0; run < 3; run++) {
Reopen(&options);
@@ -1123,6 +1147,11 @@ TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000)));
ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000)));
+ if (options.reuse_logs) {
+ // Need to force a memtable compaction since recovery does not do so.
+ ASSERT_OK(dbfull()->TEST_CompactMemTable());
+ }
+
// Check sizes across recovery by reopening a few times
for (int run = 0; run < 3; run++) {
Reopen(&options);
@@ -2084,7 +2113,8 @@ void BM_LogAndApply(int iters, int num_base_files) {
InternalKeyComparator cmp(BytewiseComparator());
Options options;
VersionSet vset(dbname, &options, NULL, &cmp);
- ASSERT_OK(vset.Recover());
+ bool save_manifest;
+ ASSERT_OK(vset.Recover(&save_manifest));
VersionEdit vbase;
uint64_t fnum = 1;
for (int i = 0; i < num_base_files; i++) {
diff --git a/src/leveldb/db/fault_injection_test.cc b/src/leveldb/db/fault_injection_test.cc
new file mode 100644
index 0000000000..875dfe81ee
--- /dev/null
+++ b/src/leveldb/db/fault_injection_test.cc
@@ -0,0 +1,554 @@
+// Copyright 2014 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.
+
+// This test uses a custom Env to keep track of the state of a filesystem as of
+// the last "sync". It then checks for data loss errors by purposely dropping
+// file data (or entire files) not protected by a "sync".
+
+#include "leveldb/db.h"
+
+#include <map>
+#include <set>
+#include "db/db_impl.h"
+#include "db/filename.h"
+#include "db/log_format.h"
+#include "db/version_set.h"
+#include "leveldb/cache.h"
+#include "leveldb/env.h"
+#include "leveldb/table.h"
+#include "leveldb/write_batch.h"
+#include "util/logging.h"
+#include "util/mutexlock.h"
+#include "util/testharness.h"
+#include "util/testutil.h"
+
+namespace leveldb {
+
+static const int kValueSize = 1000;
+static const int kMaxNumValues = 2000;
+static const size_t kNumIterations = 3;
+
+class FaultInjectionTestEnv;
+
+namespace {
+
+// Assume a filename, and not a directory name like "/foo/bar/"
+static std::string GetDirName(const std::string filename) {
+ size_t found = filename.find_last_of("/\\");
+ if (found == std::string::npos) {
+ return "";
+ } else {
+ return filename.substr(0, found);
+ }
+}
+
+Status SyncDir(const std::string& dir) {
+ // As this is a test it isn't required to *actually* sync this directory.
+ return Status::OK();
+}
+
+// A basic file truncation function suitable for this test.
+Status Truncate(const std::string& filename, uint64_t length) {
+ leveldb::Env* env = leveldb::Env::Default();
+
+ SequentialFile* orig_file;
+ Status s = env->NewSequentialFile(filename, &orig_file);
+ if (!s.ok())
+ return s;
+
+ char* scratch = new char[length];
+ leveldb::Slice result;
+ s = orig_file->Read(length, &result, scratch);
+ delete orig_file;
+ if (s.ok()) {
+ std::string tmp_name = GetDirName(filename) + "/truncate.tmp";
+ WritableFile* tmp_file;
+ s = env->NewWritableFile(tmp_name, &tmp_file);
+ if (s.ok()) {
+ s = tmp_file->Append(result);
+ delete tmp_file;
+ if (s.ok()) {
+ s = env->RenameFile(tmp_name, filename);
+ } else {
+ env->DeleteFile(tmp_name);
+ }
+ }
+ }
+
+ delete[] scratch;
+
+ return s;
+}
+
+struct FileState {
+ std::string filename_;
+ ssize_t pos_;
+ ssize_t pos_at_last_sync_;
+ ssize_t pos_at_last_flush_;
+
+ FileState(const std::string& filename)
+ : filename_(filename),
+ pos_(-1),
+ pos_at_last_sync_(-1),
+ pos_at_last_flush_(-1) { }
+
+ FileState() : pos_(-1), pos_at_last_sync_(-1), pos_at_last_flush_(-1) {}
+
+ bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; }
+
+ Status DropUnsyncedData() const;
+};
+
+} // anonymous namespace
+
+// A wrapper around WritableFile which informs another Env whenever this file
+// is written to or sync'ed.
+class TestWritableFile : public WritableFile {
+ public:
+ TestWritableFile(const FileState& state,
+ WritableFile* f,
+ FaultInjectionTestEnv* env);
+ virtual ~TestWritableFile();
+ virtual Status Append(const Slice& data);
+ virtual Status Close();
+ virtual Status Flush();
+ virtual Status Sync();
+
+ private:
+ FileState state_;
+ WritableFile* target_;
+ bool writable_file_opened_;
+ FaultInjectionTestEnv* env_;
+
+ Status SyncParent();
+};
+
+class FaultInjectionTestEnv : public EnvWrapper {
+ public:
+ FaultInjectionTestEnv() : EnvWrapper(Env::Default()), filesystem_active_(true) {}
+ virtual ~FaultInjectionTestEnv() { }
+ virtual Status NewWritableFile(const std::string& fname,
+ WritableFile** result);
+ virtual Status NewAppendableFile(const std::string& fname,
+ WritableFile** result);
+ virtual Status DeleteFile(const std::string& f);
+ virtual Status RenameFile(const std::string& s, const std::string& t);
+
+ void WritableFileClosed(const FileState& state);
+ Status DropUnsyncedFileData();
+ Status DeleteFilesCreatedAfterLastDirSync();
+ void DirWasSynced();
+ bool IsFileCreatedSinceLastDirSync(const std::string& filename);
+ void ResetState();
+ void UntrackFile(const std::string& f);
+ // Setting the filesystem to inactive is the test equivalent to simulating a
+ // system reset. Setting to inactive will freeze our saved filesystem state so
+ // that it will stop being recorded. It can then be reset back to the state at
+ // the time of the reset.
+ bool IsFilesystemActive() const { return filesystem_active_; }
+ void SetFilesystemActive(bool active) { filesystem_active_ = active; }
+
+ private:
+ port::Mutex mutex_;
+ std::map<std::string, FileState> db_file_state_;
+ std::set<std::string> new_files_since_last_dir_sync_;
+ bool filesystem_active_; // Record flushes, syncs, writes
+};
+
+TestWritableFile::TestWritableFile(const FileState& state,
+ WritableFile* f,
+ FaultInjectionTestEnv* env)
+ : state_(state),
+ target_(f),
+ writable_file_opened_(true),
+ env_(env) {
+ assert(f != NULL);
+}
+
+TestWritableFile::~TestWritableFile() {
+ if (writable_file_opened_) {
+ Close();
+ }
+ delete target_;
+}
+
+Status TestWritableFile::Append(const Slice& data) {
+ Status s = target_->Append(data);
+ if (s.ok() && env_->IsFilesystemActive()) {
+ state_.pos_ += data.size();
+ }
+ return s;
+}
+
+Status TestWritableFile::Close() {
+ writable_file_opened_ = false;
+ Status s = target_->Close();
+ if (s.ok()) {
+ env_->WritableFileClosed(state_);
+ }
+ return s;
+}
+
+Status TestWritableFile::Flush() {
+ Status s = target_->Flush();
+ if (s.ok() && env_->IsFilesystemActive()) {
+ state_.pos_at_last_flush_ = state_.pos_;
+ }
+ return s;
+}
+
+Status TestWritableFile::SyncParent() {
+ Status s = SyncDir(GetDirName(state_.filename_));
+ if (s.ok()) {
+ env_->DirWasSynced();
+ }
+ return s;
+}
+
+Status TestWritableFile::Sync() {
+ if (!env_->IsFilesystemActive()) {
+ return Status::OK();
+ }
+ // Ensure new files referred to by the manifest are in the filesystem.
+ Status s = target_->Sync();
+ if (s.ok()) {
+ state_.pos_at_last_sync_ = state_.pos_;
+ }
+ if (env_->IsFileCreatedSinceLastDirSync(state_.filename_)) {
+ Status ps = SyncParent();
+ if (s.ok() && !ps.ok()) {
+ s = ps;
+ }
+ }
+ return s;
+}
+
+Status FaultInjectionTestEnv::NewWritableFile(const std::string& fname,
+ WritableFile** result) {
+ WritableFile* actual_writable_file;
+ Status s = target()->NewWritableFile(fname, &actual_writable_file);
+ if (s.ok()) {
+ FileState state(fname);
+ state.pos_ = 0;
+ *result = new TestWritableFile(state, actual_writable_file, this);
+ // NewWritableFile doesn't append to files, so if the same file is
+ // opened again then it will be truncated - so forget our saved
+ // state.
+ UntrackFile(fname);
+ MutexLock l(&mutex_);
+ new_files_since_last_dir_sync_.insert(fname);
+ }
+ return s;
+}
+
+Status FaultInjectionTestEnv::NewAppendableFile(const std::string& fname,
+ WritableFile** result) {
+ WritableFile* actual_writable_file;
+ Status s = target()->NewAppendableFile(fname, &actual_writable_file);
+ if (s.ok()) {
+ FileState state(fname);
+ state.pos_ = 0;
+ {
+ MutexLock l(&mutex_);
+ if (db_file_state_.count(fname) == 0) {
+ new_files_since_last_dir_sync_.insert(fname);
+ } else {
+ state = db_file_state_[fname];
+ }
+ }
+ *result = new TestWritableFile(state, actual_writable_file, this);
+ }
+ return s;
+}
+
+Status FaultInjectionTestEnv::DropUnsyncedFileData() {
+ Status s;
+ MutexLock l(&mutex_);
+ for (std::map<std::string, FileState>::const_iterator it =
+ db_file_state_.begin();
+ s.ok() && it != db_file_state_.end(); ++it) {
+ const FileState& state = it->second;
+ if (!state.IsFullySynced()) {
+ s = state.DropUnsyncedData();
+ }
+ }
+ return s;
+}
+
+void FaultInjectionTestEnv::DirWasSynced() {
+ MutexLock l(&mutex_);
+ new_files_since_last_dir_sync_.clear();
+}
+
+bool FaultInjectionTestEnv::IsFileCreatedSinceLastDirSync(
+ const std::string& filename) {
+ MutexLock l(&mutex_);
+ return new_files_since_last_dir_sync_.find(filename) !=
+ new_files_since_last_dir_sync_.end();
+}
+
+void FaultInjectionTestEnv::UntrackFile(const std::string& f) {
+ MutexLock l(&mutex_);
+ db_file_state_.erase(f);
+ new_files_since_last_dir_sync_.erase(f);
+}
+
+Status FaultInjectionTestEnv::DeleteFile(const std::string& f) {
+ Status s = EnvWrapper::DeleteFile(f);
+ ASSERT_OK(s);
+ if (s.ok()) {
+ UntrackFile(f);
+ }
+ return s;
+}
+
+Status FaultInjectionTestEnv::RenameFile(const std::string& s,
+ const std::string& t) {
+ Status ret = EnvWrapper::RenameFile(s, t);
+
+ if (ret.ok()) {
+ MutexLock l(&mutex_);
+ if (db_file_state_.find(s) != db_file_state_.end()) {
+ db_file_state_[t] = db_file_state_[s];
+ db_file_state_.erase(s);
+ }
+
+ if (new_files_since_last_dir_sync_.erase(s) != 0) {
+ assert(new_files_since_last_dir_sync_.find(t) ==
+ new_files_since_last_dir_sync_.end());
+ new_files_since_last_dir_sync_.insert(t);
+ }
+ }
+
+ return ret;
+}
+
+void FaultInjectionTestEnv::ResetState() {
+ // Since we are not destroying the database, the existing files
+ // should keep their recorded synced/flushed state. Therefore
+ // we do not reset db_file_state_ and new_files_since_last_dir_sync_.
+ MutexLock l(&mutex_);
+ SetFilesystemActive(true);
+}
+
+Status FaultInjectionTestEnv::DeleteFilesCreatedAfterLastDirSync() {
+ // Because DeleteFile access this container make a copy to avoid deadlock
+ mutex_.Lock();
+ std::set<std::string> new_files(new_files_since_last_dir_sync_.begin(),
+ new_files_since_last_dir_sync_.end());
+ mutex_.Unlock();
+ Status s;
+ std::set<std::string>::const_iterator it;
+ for (it = new_files.begin(); s.ok() && it != new_files.end(); ++it) {
+ s = DeleteFile(*it);
+ }
+ return s;
+}
+
+void FaultInjectionTestEnv::WritableFileClosed(const FileState& state) {
+ MutexLock l(&mutex_);
+ db_file_state_[state.filename_] = state;
+}
+
+Status FileState::DropUnsyncedData() const {
+ ssize_t sync_pos = pos_at_last_sync_ == -1 ? 0 : pos_at_last_sync_;
+ return Truncate(filename_, sync_pos);
+}
+
+class FaultInjectionTest {
+ public:
+ enum ExpectedVerifResult { VAL_EXPECT_NO_ERROR, VAL_EXPECT_ERROR };
+ enum ResetMethod { RESET_DROP_UNSYNCED_DATA, RESET_DELETE_UNSYNCED_FILES };
+
+ FaultInjectionTestEnv* env_;
+ std::string dbname_;
+ Cache* tiny_cache_;
+ Options options_;
+ DB* db_;
+
+ FaultInjectionTest()
+ : env_(new FaultInjectionTestEnv),
+ tiny_cache_(NewLRUCache(100)),
+ db_(NULL) {
+ dbname_ = test::TmpDir() + "/fault_test";
+ DestroyDB(dbname_, Options()); // Destroy any db from earlier run
+ options_.reuse_logs = true;
+ options_.env = env_;
+ options_.paranoid_checks = true;
+ options_.block_cache = tiny_cache_;
+ options_.create_if_missing = true;
+ }
+
+ ~FaultInjectionTest() {
+ CloseDB();
+ DestroyDB(dbname_, Options());
+ delete tiny_cache_;
+ delete env_;
+ }
+
+ void ReuseLogs(bool reuse) {
+ options_.reuse_logs = reuse;
+ }
+
+ void Build(int start_idx, int num_vals) {
+ std::string key_space, value_space;
+ WriteBatch batch;
+ for (int i = start_idx; i < start_idx + num_vals; i++) {
+ Slice key = Key(i, &key_space);
+ batch.Clear();
+ batch.Put(key, Value(i, &value_space));
+ WriteOptions options;
+ ASSERT_OK(db_->Write(options, &batch));
+ }
+ }
+
+ Status ReadValue(int i, std::string* val) const {
+ std::string key_space, value_space;
+ Slice key = Key(i, &key_space);
+ Value(i, &value_space);
+ ReadOptions options;
+ return db_->Get(options, key, val);
+ }
+
+ Status Verify(int start_idx, int num_vals,
+ ExpectedVerifResult expected) const {
+ std::string val;
+ std::string value_space;
+ Status s;
+ for (int i = start_idx; i < start_idx + num_vals && s.ok(); i++) {
+ Value(i, &value_space);
+ s = ReadValue(i, &val);
+ if (expected == VAL_EXPECT_NO_ERROR) {
+ if (s.ok()) {
+ ASSERT_EQ(value_space, val);
+ }
+ } else if (s.ok()) {
+ fprintf(stderr, "Expected an error at %d, but was OK\n", i);
+ s = Status::IOError(dbname_, "Expected value error:");
+ } else {
+ s = Status::OK(); // An expected error
+ }
+ }
+ return s;
+ }
+
+ // Return the ith key
+ Slice Key(int i, std::string* storage) const {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%016d", i);
+ storage->assign(buf, strlen(buf));
+ return Slice(*storage);
+ }
+
+ // Return the value to associate with the specified key
+ Slice Value(int k, std::string* storage) const {
+ Random r(k);
+ return test::RandomString(&r, kValueSize, storage);
+ }
+
+ Status OpenDB() {
+ delete db_;
+ db_ = NULL;
+ env_->ResetState();
+ return DB::Open(options_, dbname_, &db_);
+ }
+
+ void CloseDB() {
+ delete db_;
+ db_ = NULL;
+ }
+
+ void DeleteAllData() {
+ Iterator* iter = db_->NewIterator(ReadOptions());
+ WriteOptions options;
+ for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
+ ASSERT_OK(db_->Delete(WriteOptions(), iter->key()));
+ }
+
+ delete iter;
+ }
+
+ void ResetDBState(ResetMethod reset_method) {
+ switch (reset_method) {
+ case RESET_DROP_UNSYNCED_DATA:
+ ASSERT_OK(env_->DropUnsyncedFileData());
+ break;
+ case RESET_DELETE_UNSYNCED_FILES:
+ ASSERT_OK(env_->DeleteFilesCreatedAfterLastDirSync());
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+ void PartialCompactTestPreFault(int num_pre_sync, int num_post_sync) {
+ DeleteAllData();
+ Build(0, num_pre_sync);
+ db_->CompactRange(NULL, NULL);
+ Build(num_pre_sync, num_post_sync);
+ }
+
+ void PartialCompactTestReopenWithFault(ResetMethod reset_method,
+ int num_pre_sync,
+ int num_post_sync) {
+ env_->SetFilesystemActive(false);
+ CloseDB();
+ ResetDBState(reset_method);
+ ASSERT_OK(OpenDB());
+ ASSERT_OK(Verify(0, num_pre_sync, FaultInjectionTest::VAL_EXPECT_NO_ERROR));
+ ASSERT_OK(Verify(num_pre_sync, num_post_sync, FaultInjectionTest::VAL_EXPECT_ERROR));
+ }
+
+ void NoWriteTestPreFault() {
+ }
+
+ void NoWriteTestReopenWithFault(ResetMethod reset_method) {
+ CloseDB();
+ ResetDBState(reset_method);
+ ASSERT_OK(OpenDB());
+ }
+
+ void DoTest() {
+ Random rnd(0);
+ ASSERT_OK(OpenDB());
+ for (size_t idx = 0; idx < kNumIterations; idx++) {
+ int num_pre_sync = rnd.Uniform(kMaxNumValues);
+ int num_post_sync = rnd.Uniform(kMaxNumValues);
+
+ PartialCompactTestPreFault(num_pre_sync, num_post_sync);
+ PartialCompactTestReopenWithFault(RESET_DROP_UNSYNCED_DATA,
+ num_pre_sync,
+ num_post_sync);
+
+ NoWriteTestPreFault();
+ NoWriteTestReopenWithFault(RESET_DROP_UNSYNCED_DATA);
+
+ PartialCompactTestPreFault(num_pre_sync, num_post_sync);
+ // No new files created so we expect all values since no files will be
+ // dropped.
+ PartialCompactTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES,
+ num_pre_sync + num_post_sync,
+ 0);
+
+ NoWriteTestPreFault();
+ NoWriteTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES);
+ }
+ }
+};
+
+TEST(FaultInjectionTest, FaultTestNoLogReuse) {
+ ReuseLogs(false);
+ DoTest();
+}
+
+TEST(FaultInjectionTest, FaultTestWithLogReuse) {
+ ReuseLogs(true);
+ DoTest();
+}
+
+} // namespace leveldb
+
+int main(int argc, char** argv) {
+ return leveldb::test::RunAllTests();
+}
diff --git a/src/leveldb/db/leveldb_main.cc b/src/leveldb/db/leveldbutil.cc
index 9f4b7dd70c..9f4b7dd70c 100644
--- a/src/leveldb/db/leveldb_main.cc
+++ b/src/leveldb/db/leveldbutil.cc
diff --git a/src/leveldb/db/log_reader.cc b/src/leveldb/db/log_reader.cc
index e44b66c85b..a6d304545d 100644
--- a/src/leveldb/db/log_reader.cc
+++ b/src/leveldb/db/log_reader.cc
@@ -25,7 +25,8 @@ Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum,
eof_(false),
last_record_offset_(0),
end_of_buffer_offset_(0),
- initial_offset_(initial_offset) {
+ initial_offset_(initial_offset),
+ resyncing_(initial_offset > 0) {
}
Reader::~Reader() {
@@ -72,8 +73,25 @@ bool Reader::ReadRecord(Slice* record, std::string* scratch) {
Slice fragment;
while (true) {
- uint64_t physical_record_offset = end_of_buffer_offset_ - buffer_.size();
const unsigned int record_type = ReadPhysicalRecord(&fragment);
+
+ // ReadPhysicalRecord may have only had an empty trailer remaining in its
+ // internal buffer. Calculate the offset of the next physical record now
+ // that it has returned, properly accounting for its header size.
+ uint64_t physical_record_offset =
+ end_of_buffer_offset_ - buffer_.size() - kHeaderSize - fragment.size();
+
+ if (resyncing_) {
+ if (record_type == kMiddleType) {
+ continue;
+ } else if (record_type == kLastType) {
+ resyncing_ = false;
+ continue;
+ } else {
+ resyncing_ = false;
+ }
+ }
+
switch (record_type) {
case kFullType:
if (in_fragmented_record) {
diff --git a/src/leveldb/db/log_reader.h b/src/leveldb/db/log_reader.h
index 6aff791716..8389d61f8f 100644
--- a/src/leveldb/db/log_reader.h
+++ b/src/leveldb/db/log_reader.h
@@ -73,6 +73,11 @@ class Reader {
// Offset at which to start looking for the first record to return
uint64_t const initial_offset_;
+ // True if we are resynchronizing after a seek (initial_offset_ > 0). In
+ // particular, a run of kMiddleType and kLastType records can be silently
+ // skipped in this mode
+ bool resyncing_;
+
// Extend record types with the following special values
enum {
kEof = kMaxRecordType + 1,
diff --git a/src/leveldb/db/log_test.cc b/src/leveldb/db/log_test.cc
index dcf0562652..48a5928657 100644
--- a/src/leveldb/db/log_test.cc
+++ b/src/leveldb/db/log_test.cc
@@ -79,7 +79,7 @@ class LogTest {
virtual Status Skip(uint64_t n) {
if (n > contents_.size()) {
contents_.clear();
- return Status::NotFound("in-memory file skipepd past end");
+ return Status::NotFound("in-memory file skipped past end");
}
contents_.remove_prefix(n);
@@ -104,23 +104,34 @@ class LogTest {
StringSource source_;
ReportCollector report_;
bool reading_;
- Writer writer_;
- Reader reader_;
+ Writer* writer_;
+ Reader* reader_;
// Record metadata for testing initial offset functionality
static size_t initial_offset_record_sizes_[];
static uint64_t initial_offset_last_record_offsets_[];
+ static int num_initial_offset_records_;
public:
LogTest() : reading_(false),
- writer_(&dest_),
- reader_(&source_, &report_, true/*checksum*/,
- 0/*initial_offset*/) {
+ writer_(new Writer(&dest_)),
+ reader_(new Reader(&source_, &report_, true/*checksum*/,
+ 0/*initial_offset*/)) {
+ }
+
+ ~LogTest() {
+ delete writer_;
+ delete reader_;
+ }
+
+ void ReopenForAppend() {
+ delete writer_;
+ writer_ = new Writer(&dest_, dest_.contents_.size());
}
void Write(const std::string& msg) {
ASSERT_TRUE(!reading_) << "Write() after starting to read";
- writer_.AddRecord(Slice(msg));
+ writer_->AddRecord(Slice(msg));
}
size_t WrittenBytes() const {
@@ -134,7 +145,7 @@ class LogTest {
}
std::string scratch;
Slice record;
- if (reader_.ReadRecord(&record, &scratch)) {
+ if (reader_->ReadRecord(&record, &scratch)) {
return record.ToString();
} else {
return "EOF";
@@ -182,13 +193,18 @@ class LogTest {
}
void WriteInitialOffsetLog() {
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < num_initial_offset_records_; i++) {
std::string record(initial_offset_record_sizes_[i],
static_cast<char>('a' + i));
Write(record);
}
}
+ void StartReadingAt(uint64_t initial_offset) {
+ delete reader_;
+ reader_ = new Reader(&source_, &report_, true/*checksum*/, initial_offset);
+ }
+
void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) {
WriteInitialOffsetLog();
reading_ = true;
@@ -208,32 +224,48 @@ class LogTest {
source_.contents_ = Slice(dest_.contents_);
Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/,
initial_offset);
- Slice record;
- std::string scratch;
- ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch));
- ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset],
- record.size());
- ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset],
- offset_reader->LastRecordOffset());
- ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]);
+
+ // Read all records from expected_record_offset through the last one.
+ ASSERT_LT(expected_record_offset, num_initial_offset_records_);
+ for (; expected_record_offset < num_initial_offset_records_;
+ ++expected_record_offset) {
+ Slice record;
+ std::string scratch;
+ ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch));
+ ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset],
+ record.size());
+ ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset],
+ offset_reader->LastRecordOffset());
+ ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]);
+ }
delete offset_reader;
}
-
};
size_t LogTest::initial_offset_record_sizes_[] =
{10000, // Two sizable records in first block
10000,
2 * log::kBlockSize - 1000, // Span three blocks
- 1};
+ 1,
+ 13716, // Consume all but two bytes of block 3.
+ log::kBlockSize - kHeaderSize, // Consume the entirety of block 4.
+ };
uint64_t LogTest::initial_offset_last_record_offsets_[] =
{0,
kHeaderSize + 10000,
2 * (kHeaderSize + 10000),
2 * (kHeaderSize + 10000) +
- (2 * log::kBlockSize - 1000) + 3 * kHeaderSize};
+ (2 * log::kBlockSize - 1000) + 3 * kHeaderSize,
+ 2 * (kHeaderSize + 10000) +
+ (2 * log::kBlockSize - 1000) + 3 * kHeaderSize
+ + kHeaderSize + 1,
+ 3 * log::kBlockSize,
+ };
+// LogTest::initial_offset_last_record_offsets_ must be defined before this.
+int LogTest::num_initial_offset_records_ =
+ sizeof(LogTest::initial_offset_last_record_offsets_)/sizeof(uint64_t);
TEST(LogTest, Empty) {
ASSERT_EQ("EOF", Read());
@@ -318,6 +350,15 @@ TEST(LogTest, AlignedEof) {
ASSERT_EQ("EOF", Read());
}
+TEST(LogTest, OpenForAppend) {
+ Write("hello");
+ ReopenForAppend();
+ Write("world");
+ ASSERT_EQ("hello", Read());
+ ASSERT_EQ("world", Read());
+ ASSERT_EQ("EOF", Read());
+}
+
TEST(LogTest, RandomRead) {
const int N = 500;
Random write_rnd(301);
@@ -445,6 +486,22 @@ TEST(LogTest, PartialLastIsIgnored) {
ASSERT_EQ(0, DroppedBytes());
}
+TEST(LogTest, SkipIntoMultiRecord) {
+ // Consider a fragmented record:
+ // first(R1), middle(R1), last(R1), first(R2)
+ // If initial_offset points to a record after first(R1) but before first(R2)
+ // incomplete fragment errors are not actual errors, and must be suppressed
+ // until a new first or full record is encountered.
+ Write(BigString("foo", 3*kBlockSize));
+ Write("correct");
+ StartReadingAt(kBlockSize);
+
+ ASSERT_EQ("correct", Read());
+ ASSERT_EQ("", ReportMessage());
+ ASSERT_EQ(0, DroppedBytes());
+ ASSERT_EQ("EOF", Read());
+}
+
TEST(LogTest, ErrorJoinsRecords) {
// Consider two fragmented records:
// first(R1) last(R1) first(R2) last(R2)
@@ -514,6 +571,10 @@ TEST(LogTest, ReadFourthStart) {
3);
}
+TEST(LogTest, ReadInitialOffsetIntoBlockPadding) {
+ CheckInitialOffsetRecord(3 * log::kBlockSize - 3, 5);
+}
+
TEST(LogTest, ReadEnd) {
CheckOffsetPastEndReturnsNoRecords(0);
}
diff --git a/src/leveldb/db/log_writer.cc b/src/leveldb/db/log_writer.cc
index 2da99ac088..74a03270da 100644
--- a/src/leveldb/db/log_writer.cc
+++ b/src/leveldb/db/log_writer.cc
@@ -12,15 +12,24 @@
namespace leveldb {
namespace log {
-Writer::Writer(WritableFile* dest)
- : dest_(dest),
- block_offset_(0) {
+static void InitTypeCrc(uint32_t* type_crc) {
for (int i = 0; i <= kMaxRecordType; i++) {
char t = static_cast<char>(i);
- type_crc_[i] = crc32c::Value(&t, 1);
+ type_crc[i] = crc32c::Value(&t, 1);
}
}
+Writer::Writer(WritableFile* dest)
+ : dest_(dest),
+ block_offset_(0) {
+ InitTypeCrc(type_crc_);
+}
+
+Writer::Writer(WritableFile* dest, uint64_t dest_length)
+ : dest_(dest), block_offset_(dest_length % kBlockSize) {
+ InitTypeCrc(type_crc_);
+}
+
Writer::~Writer() {
}
diff --git a/src/leveldb/db/log_writer.h b/src/leveldb/db/log_writer.h
index a3a954d967..9e7cc4705b 100644
--- a/src/leveldb/db/log_writer.h
+++ b/src/leveldb/db/log_writer.h
@@ -22,6 +22,12 @@ class Writer {
// "*dest" must be initially empty.
// "*dest" must remain live while this Writer is in use.
explicit Writer(WritableFile* dest);
+
+ // Create a writer that will append data to "*dest".
+ // "*dest" must have initial length "dest_length".
+ // "*dest" must remain live while this Writer is in use.
+ Writer(WritableFile* dest, uint64_t dest_length);
+
~Writer();
Status AddRecord(const Slice& slice);
diff --git a/src/leveldb/db/memtable.h b/src/leveldb/db/memtable.h
index 92e90bb099..9f41567cde 100644
--- a/src/leveldb/db/memtable.h
+++ b/src/leveldb/db/memtable.h
@@ -36,10 +36,7 @@ class MemTable {
}
// Returns an estimate of the number of bytes of data in use by this
- // data structure.
- //
- // REQUIRES: external synchronization to prevent simultaneous
- // operations on the same MemTable.
+ // data structure. It is safe to call when MemTable is being modified.
size_t ApproximateMemoryUsage();
// Return an iterator that yields the contents of the memtable.
diff --git a/src/leveldb/db/recovery_test.cc b/src/leveldb/db/recovery_test.cc
new file mode 100644
index 0000000000..9596f4288a
--- /dev/null
+++ b/src/leveldb/db/recovery_test.cc
@@ -0,0 +1,324 @@
+// Copyright (c) 2014 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 "db/db_impl.h"
+#include "db/filename.h"
+#include "db/version_set.h"
+#include "db/write_batch_internal.h"
+#include "leveldb/db.h"
+#include "leveldb/env.h"
+#include "leveldb/write_batch.h"
+#include "util/logging.h"
+#include "util/testharness.h"
+#include "util/testutil.h"
+
+namespace leveldb {
+
+class RecoveryTest {
+ public:
+ RecoveryTest() : env_(Env::Default()), db_(NULL) {
+ dbname_ = test::TmpDir() + "/recovery_test";
+ DestroyDB(dbname_, Options());
+ Open();
+ }
+
+ ~RecoveryTest() {
+ Close();
+ DestroyDB(dbname_, Options());
+ }
+
+ DBImpl* dbfull() const { return reinterpret_cast<DBImpl*>(db_); }
+ Env* env() const { return env_; }
+
+ bool CanAppend() {
+ WritableFile* tmp;
+ Status s = env_->NewAppendableFile(CurrentFileName(dbname_), &tmp);
+ delete tmp;
+ if (s.IsNotSupportedError()) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ void Close() {
+ delete db_;
+ db_ = NULL;
+ }
+
+ void Open(Options* options = NULL) {
+ Close();
+ Options opts;
+ if (options != NULL) {
+ opts = *options;
+ } else {
+ opts.reuse_logs = true; // TODO(sanjay): test both ways
+ opts.create_if_missing = true;
+ }
+ if (opts.env == NULL) {
+ opts.env = env_;
+ }
+ ASSERT_OK(DB::Open(opts, dbname_, &db_));
+ ASSERT_EQ(1, NumLogs());
+ }
+
+ Status Put(const std::string& k, const std::string& v) {
+ return db_->Put(WriteOptions(), k, v);
+ }
+
+ std::string Get(const std::string& k, const Snapshot* snapshot = NULL) {
+ std::string result;
+ Status s = db_->Get(ReadOptions(), k, &result);
+ if (s.IsNotFound()) {
+ result = "NOT_FOUND";
+ } else if (!s.ok()) {
+ result = s.ToString();
+ }
+ return result;
+ }
+
+ std::string ManifestFileName() {
+ std::string current;
+ ASSERT_OK(ReadFileToString(env_, CurrentFileName(dbname_), &current));
+ size_t len = current.size();
+ if (len > 0 && current[len-1] == '\n') {
+ current.resize(len - 1);
+ }
+ return dbname_ + "/" + current;
+ }
+
+ std::string LogName(uint64_t number) {
+ return LogFileName(dbname_, number);
+ }
+
+ size_t DeleteLogFiles() {
+ std::vector<uint64_t> logs = GetFiles(kLogFile);
+ for (size_t i = 0; i < logs.size(); i++) {
+ ASSERT_OK(env_->DeleteFile(LogName(logs[i]))) << LogName(logs[i]);
+ }
+ return logs.size();
+ }
+
+ uint64_t FirstLogFile() {
+ return GetFiles(kLogFile)[0];
+ }
+
+ std::vector<uint64_t> GetFiles(FileType t) {
+ std::vector<std::string> filenames;
+ ASSERT_OK(env_->GetChildren(dbname_, &filenames));
+ std::vector<uint64_t> result;
+ for (size_t i = 0; i < filenames.size(); i++) {
+ uint64_t number;
+ FileType type;
+ if (ParseFileName(filenames[i], &number, &type) && type == t) {
+ result.push_back(number);
+ }
+ }
+ return result;
+ }
+
+ int NumLogs() {
+ return GetFiles(kLogFile).size();
+ }
+
+ int NumTables() {
+ return GetFiles(kTableFile).size();
+ }
+
+ uint64_t FileSize(const std::string& fname) {
+ uint64_t result;
+ ASSERT_OK(env_->GetFileSize(fname, &result)) << fname;
+ return result;
+ }
+
+ void CompactMemTable() {
+ dbfull()->TEST_CompactMemTable();
+ }
+
+ // Directly construct a log file that sets key to val.
+ void MakeLogFile(uint64_t lognum, SequenceNumber seq, Slice key, Slice val) {
+ std::string fname = LogFileName(dbname_, lognum);
+ WritableFile* file;
+ ASSERT_OK(env_->NewWritableFile(fname, &file));
+ log::Writer writer(file);
+ WriteBatch batch;
+ batch.Put(key, val);
+ WriteBatchInternal::SetSequence(&batch, seq);
+ ASSERT_OK(writer.AddRecord(WriteBatchInternal::Contents(&batch)));
+ ASSERT_OK(file->Flush());
+ delete file;
+ }
+
+ private:
+ std::string dbname_;
+ Env* env_;
+ DB* db_;
+};
+
+TEST(RecoveryTest, ManifestReused) {
+ if (!CanAppend()) {
+ fprintf(stderr, "skipping test because env does not support appending\n");
+ return;
+ }
+ ASSERT_OK(Put("foo", "bar"));
+ Close();
+ std::string old_manifest = ManifestFileName();
+ Open();
+ ASSERT_EQ(old_manifest, ManifestFileName());
+ ASSERT_EQ("bar", Get("foo"));
+ Open();
+ ASSERT_EQ(old_manifest, ManifestFileName());
+ ASSERT_EQ("bar", Get("foo"));
+}
+
+TEST(RecoveryTest, LargeManifestCompacted) {
+ if (!CanAppend()) {
+ fprintf(stderr, "skipping test because env does not support appending\n");
+ return;
+ }
+ ASSERT_OK(Put("foo", "bar"));
+ Close();
+ std::string old_manifest = ManifestFileName();
+
+ // Pad with zeroes to make manifest file very big.
+ {
+ uint64_t len = FileSize(old_manifest);
+ WritableFile* file;
+ ASSERT_OK(env()->NewAppendableFile(old_manifest, &file));
+ std::string zeroes(3*1048576 - static_cast<size_t>(len), 0);
+ ASSERT_OK(file->Append(zeroes));
+ ASSERT_OK(file->Flush());
+ delete file;
+ }
+
+ Open();
+ std::string new_manifest = ManifestFileName();
+ ASSERT_NE(old_manifest, new_manifest);
+ ASSERT_GT(10000, FileSize(new_manifest));
+ ASSERT_EQ("bar", Get("foo"));
+
+ Open();
+ ASSERT_EQ(new_manifest, ManifestFileName());
+ ASSERT_EQ("bar", Get("foo"));
+}
+
+TEST(RecoveryTest, NoLogFiles) {
+ ASSERT_OK(Put("foo", "bar"));
+ ASSERT_EQ(1, DeleteLogFiles());
+ Open();
+ ASSERT_EQ("NOT_FOUND", Get("foo"));
+ Open();
+ ASSERT_EQ("NOT_FOUND", Get("foo"));
+}
+
+TEST(RecoveryTest, LogFileReuse) {
+ if (!CanAppend()) {
+ fprintf(stderr, "skipping test because env does not support appending\n");
+ return;
+ }
+ for (int i = 0; i < 2; i++) {
+ ASSERT_OK(Put("foo", "bar"));
+ if (i == 0) {
+ // Compact to ensure current log is empty
+ CompactMemTable();
+ }
+ Close();
+ ASSERT_EQ(1, NumLogs());
+ uint64_t number = FirstLogFile();
+ if (i == 0) {
+ ASSERT_EQ(0, FileSize(LogName(number)));
+ } else {
+ ASSERT_LT(0, FileSize(LogName(number)));
+ }
+ Open();
+ ASSERT_EQ(1, NumLogs());
+ ASSERT_EQ(number, FirstLogFile()) << "did not reuse log file";
+ ASSERT_EQ("bar", Get("foo"));
+ Open();
+ ASSERT_EQ(1, NumLogs());
+ ASSERT_EQ(number, FirstLogFile()) << "did not reuse log file";
+ ASSERT_EQ("bar", Get("foo"));
+ }
+}
+
+TEST(RecoveryTest, MultipleMemTables) {
+ // Make a large log.
+ const int kNum = 1000;
+ for (int i = 0; i < kNum; i++) {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%050d", i);
+ ASSERT_OK(Put(buf, buf));
+ }
+ ASSERT_EQ(0, NumTables());
+ Close();
+ ASSERT_EQ(0, NumTables());
+ ASSERT_EQ(1, NumLogs());
+ uint64_t old_log_file = FirstLogFile();
+
+ // Force creation of multiple memtables by reducing the write buffer size.
+ Options opt;
+ opt.reuse_logs = true;
+ opt.write_buffer_size = (kNum*100) / 2;
+ Open(&opt);
+ ASSERT_LE(2, NumTables());
+ ASSERT_EQ(1, NumLogs());
+ ASSERT_NE(old_log_file, FirstLogFile()) << "must not reuse log";
+ for (int i = 0; i < kNum; i++) {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%050d", i);
+ ASSERT_EQ(buf, Get(buf));
+ }
+}
+
+TEST(RecoveryTest, MultipleLogFiles) {
+ ASSERT_OK(Put("foo", "bar"));
+ Close();
+ ASSERT_EQ(1, NumLogs());
+
+ // Make a bunch of uncompacted log files.
+ uint64_t old_log = FirstLogFile();
+ MakeLogFile(old_log+1, 1000, "hello", "world");
+ MakeLogFile(old_log+2, 1001, "hi", "there");
+ MakeLogFile(old_log+3, 1002, "foo", "bar2");
+
+ // Recover and check that all log files were processed.
+ Open();
+ ASSERT_LE(1, NumTables());
+ ASSERT_EQ(1, NumLogs());
+ uint64_t new_log = FirstLogFile();
+ ASSERT_LE(old_log+3, new_log);
+ ASSERT_EQ("bar2", Get("foo"));
+ ASSERT_EQ("world", Get("hello"));
+ ASSERT_EQ("there", Get("hi"));
+
+ // Test that previous recovery produced recoverable state.
+ Open();
+ ASSERT_LE(1, NumTables());
+ ASSERT_EQ(1, NumLogs());
+ if (CanAppend()) {
+ ASSERT_EQ(new_log, FirstLogFile());
+ }
+ ASSERT_EQ("bar2", Get("foo"));
+ ASSERT_EQ("world", Get("hello"));
+ ASSERT_EQ("there", Get("hi"));
+
+ // Check that introducing an older log file does not cause it to be re-read.
+ Close();
+ MakeLogFile(old_log+1, 2000, "hello", "stale write");
+ Open();
+ ASSERT_LE(1, NumTables());
+ ASSERT_EQ(1, NumLogs());
+ if (CanAppend()) {
+ ASSERT_EQ(new_log, FirstLogFile());
+ }
+ ASSERT_EQ("bar2", Get("foo"));
+ ASSERT_EQ("world", Get("hello"));
+ ASSERT_EQ("there", Get("hi"));
+}
+
+} // namespace leveldb
+
+int main(int argc, char** argv) {
+ return leveldb::test::RunAllTests();
+}
diff --git a/src/leveldb/db/skiplist.h b/src/leveldb/db/skiplist.h
index ed8b092203..8bd77764d8 100644
--- a/src/leveldb/db/skiplist.h
+++ b/src/leveldb/db/skiplist.h
@@ -1,10 +1,10 @@
-#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_
-#define STORAGE_LEVELDB_DB_SKIPLIST_H_
-
// 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.
-//
+
+#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_
+#define STORAGE_LEVELDB_DB_SKIPLIST_H_
+
// Thread safety
// -------------
//
diff --git a/src/leveldb/db/skiplist_test.cc b/src/leveldb/db/skiplist_test.cc
index c78f4b4fb1..aee1461e1b 100644
--- a/src/leveldb/db/skiplist_test.cc
+++ b/src/leveldb/db/skiplist_test.cc
@@ -250,7 +250,7 @@ class ConcurrentTest {
// Note that generation 0 is never inserted, so it is ok if
// <*,0,*> is missing.
ASSERT_TRUE((gen(pos) == 0) ||
- (gen(pos) > initial_state.Get(key(pos)))
+ (gen(pos) > static_cast<Key>(initial_state.Get(key(pos))))
) << "key: " << key(pos)
<< "; gen: " << gen(pos)
<< "; initgen: "
diff --git a/src/leveldb/db/snapshot.h b/src/leveldb/db/snapshot.h
index e7f8fd2c37..6ed413c42d 100644
--- a/src/leveldb/db/snapshot.h
+++ b/src/leveldb/db/snapshot.h
@@ -5,6 +5,7 @@
#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_
#define STORAGE_LEVELDB_DB_SNAPSHOT_H_
+#include "db/dbformat.h"
#include "leveldb/db.h"
namespace leveldb {
diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc
index aa83df55e4..a5e0f77a6a 100644
--- a/src/leveldb/db/version_set.cc
+++ b/src/leveldb/db/version_set.cc
@@ -893,7 +893,7 @@ Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) {
return s;
}
-Status VersionSet::Recover() {
+Status VersionSet::Recover(bool *save_manifest) {
struct LogReporter : public log::Reader::Reporter {
Status* status;
virtual void Corruption(size_t bytes, const Status& s) {
@@ -1003,11 +1003,49 @@ Status VersionSet::Recover() {
last_sequence_ = last_sequence;
log_number_ = log_number;
prev_log_number_ = prev_log_number;
+
+ // See if we can reuse the existing MANIFEST file.
+ if (ReuseManifest(dscname, current)) {
+ // No need to save new manifest
+ } else {
+ *save_manifest = true;
+ }
}
return s;
}
+bool VersionSet::ReuseManifest(const std::string& dscname,
+ const std::string& dscbase) {
+ if (!options_->reuse_logs) {
+ return false;
+ }
+ FileType manifest_type;
+ uint64_t manifest_number;
+ uint64_t manifest_size;
+ if (!ParseFileName(dscbase, &manifest_number, &manifest_type) ||
+ manifest_type != kDescriptorFile ||
+ !env_->GetFileSize(dscname, &manifest_size).ok() ||
+ // Make new compacted MANIFEST if old one is too big
+ manifest_size >= kTargetFileSize) {
+ return false;
+ }
+
+ assert(descriptor_file_ == NULL);
+ assert(descriptor_log_ == NULL);
+ Status r = env_->NewAppendableFile(dscname, &descriptor_file_);
+ if (!r.ok()) {
+ Log(options_->info_log, "Reuse MANIFEST: %s\n", r.ToString().c_str());
+ assert(descriptor_file_ == NULL);
+ return false;
+ }
+
+ Log(options_->info_log, "Reusing MANIFEST %s\n", dscname.c_str());
+ descriptor_log_ = new log::Writer(descriptor_file_, manifest_size);
+ manifest_file_number_ = manifest_number;
+ return true;
+}
+
void VersionSet::MarkFileNumberUsed(uint64_t number) {
if (next_file_number_ <= number) {
next_file_number_ = number + 1;
diff --git a/src/leveldb/db/version_set.h b/src/leveldb/db/version_set.h
index 8dc14b8e01..1dec745673 100644
--- a/src/leveldb/db/version_set.h
+++ b/src/leveldb/db/version_set.h
@@ -179,7 +179,7 @@ class VersionSet {
EXCLUSIVE_LOCKS_REQUIRED(mu);
// Recover the last saved descriptor from persistent storage.
- Status Recover();
+ Status Recover(bool *save_manifest);
// Return the current version.
Version* current() const { return current_; }
@@ -274,6 +274,8 @@ class VersionSet {
friend class Compaction;
friend class Version;
+ bool ReuseManifest(const std::string& dscname, const std::string& dscbase);
+
void Finalize(Version* v);
void GetRange(const std::vector<FileMetaData*>& inputs,
diff --git a/src/leveldb/db/write_batch_internal.h b/src/leveldb/db/write_batch_internal.h
index 310a3c8912..9448ef7b21 100644
--- a/src/leveldb/db/write_batch_internal.h
+++ b/src/leveldb/db/write_batch_internal.h
@@ -5,6 +5,7 @@
#ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_
#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_
+#include "db/dbformat.h"
#include "leveldb/write_batch.h"
namespace leveldb {
diff --git a/src/leveldb/doc/index.html b/src/leveldb/doc/index.html
index 3ed0ed9d9e..2155192581 100644
--- a/src/leveldb/doc/index.html
+++ b/src/leveldb/doc/index.html
@@ -22,7 +22,7 @@ directory. The following example shows how to open a database,
creating it if necessary:
<p>
<pre>
- #include &lt;assert&gt;
+ #include &lt;cassert&gt;
#include "leveldb/db.h"
leveldb::DB* db;
diff --git a/src/leveldb/helpers/memenv/memenv.cc b/src/leveldb/helpers/memenv/memenv.cc
index 43ef2e0729..9a98884daf 100644
--- a/src/leveldb/helpers/memenv/memenv.cc
+++ b/src/leveldb/helpers/memenv/memenv.cc
@@ -277,6 +277,19 @@ class InMemoryEnv : public EnvWrapper {
return Status::OK();
}
+ virtual Status NewAppendableFile(const std::string& fname,
+ WritableFile** result) {
+ MutexLock lock(&mutex_);
+ FileState** sptr = &file_map_[fname];
+ FileState* file = *sptr;
+ if (file == NULL) {
+ file = new FileState();
+ file->Ref();
+ }
+ *result = new WritableFileImpl(file);
+ return Status::OK();
+ }
+
virtual bool FileExists(const std::string& fname) {
MutexLock lock(&mutex_);
return file_map_.find(fname) != file_map_.end();
diff --git a/src/leveldb/helpers/memenv/memenv_test.cc b/src/leveldb/helpers/memenv/memenv_test.cc
index a44310fed8..5cff77613f 100644
--- a/src/leveldb/helpers/memenv/memenv_test.cc
+++ b/src/leveldb/helpers/memenv/memenv_test.cc
@@ -40,6 +40,8 @@ TEST(MemEnvTest, Basics) {
// Create a file.
ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file));
+ ASSERT_OK(env_->GetFileSize("/dir/f", &file_size));
+ ASSERT_EQ(0, file_size);
delete writable_file;
// Check that the file exists.
@@ -55,9 +57,16 @@ TEST(MemEnvTest, Basics) {
ASSERT_OK(writable_file->Append("abc"));
delete writable_file;
- // Check for expected size.
+ // Check that append works.
+ ASSERT_OK(env_->NewAppendableFile("/dir/f", &writable_file));
ASSERT_OK(env_->GetFileSize("/dir/f", &file_size));
ASSERT_EQ(3, file_size);
+ ASSERT_OK(writable_file->Append("hello"));
+ delete writable_file;
+
+ // Check for expected size.
+ ASSERT_OK(env_->GetFileSize("/dir/f", &file_size));
+ ASSERT_EQ(8, file_size);
// Check that renaming works.
ASSERT_TRUE(!env_->RenameFile("/dir/non_existent", "/dir/g").ok());
@@ -65,7 +74,7 @@ TEST(MemEnvTest, Basics) {
ASSERT_TRUE(!env_->FileExists("/dir/f"));
ASSERT_TRUE(env_->FileExists("/dir/g"));
ASSERT_OK(env_->GetFileSize("/dir/g", &file_size));
- ASSERT_EQ(3, file_size);
+ ASSERT_EQ(8, file_size);
// Check that opening non-existent file fails.
SequentialFile* seq_file;
diff --git a/src/leveldb/include/leveldb/cache.h b/src/leveldb/include/leveldb/cache.h
index 1a201e5e0a..6819d5bc49 100644
--- a/src/leveldb/include/leveldb/cache.h
+++ b/src/leveldb/include/leveldb/cache.h
@@ -81,6 +81,17 @@ class Cache {
// its cache keys.
virtual uint64_t NewId() = 0;
+ // Remove all cache entries that are not actively in use. Memory-constrained
+ // applications may wish to call this method to reduce memory usage.
+ // Default implementation of Prune() does nothing. Subclasses are strongly
+ // encouraged to override the default implementation. A future release of
+ // leveldb may change Prune() to a pure abstract method.
+ virtual void Prune() {}
+
+ // Return an estimate of the combined charges of all elements stored in the
+ // cache.
+ virtual size_t TotalCharge() const = 0;
+
private:
void LRU_Remove(Handle* e);
void LRU_Append(Handle* e);
diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h
index 4c169bf22e..9752cbad51 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 = 18;
+static const int kMinorVersion = 19;
struct Options;
struct ReadOptions;
@@ -115,6 +115,8 @@ class DB {
// about the internal operation of the DB.
// "leveldb.sstables" - returns a multi-line string that describes all
// of the sstables that make up the db contents.
+ // "leveldb.approximate-memory-usage" - returns the approximate number of
+ // bytes of memory in use by the DB.
virtual bool GetProperty(const Slice& property, std::string* value) = 0;
// For each i in [0,n-1], store in "sizes[i]", the approximate
diff --git a/src/leveldb/include/leveldb/env.h b/src/leveldb/include/leveldb/env.h
index f709514da6..99b6c21414 100644
--- a/src/leveldb/include/leveldb/env.h
+++ b/src/leveldb/include/leveldb/env.h
@@ -69,6 +69,21 @@ class Env {
virtual Status NewWritableFile(const std::string& fname,
WritableFile** result) = 0;
+ // Create an object that either appends to an existing file, or
+ // writes to a new file (if the file does not exist to begin with).
+ // On success, stores a pointer to the new file in *result and
+ // returns OK. On failure stores NULL in *result and returns
+ // non-OK.
+ //
+ // The returned file will only be accessed by one thread at a time.
+ //
+ // May return an IsNotSupportedError error if this Env does
+ // not allow appending to an existing file. Users of Env (including
+ // the leveldb implementation) must be prepared to deal with
+ // an Env that does not support appending.
+ virtual Status NewAppendableFile(const std::string& fname,
+ WritableFile** result);
+
// Returns true iff the named file exists.
virtual bool FileExists(const std::string& fname) = 0;
@@ -289,6 +304,9 @@ class EnvWrapper : public Env {
Status NewWritableFile(const std::string& f, WritableFile** r) {
return target_->NewWritableFile(f, r);
}
+ Status NewAppendableFile(const std::string& f, WritableFile** r) {
+ return target_->NewAppendableFile(f, r);
+ }
bool FileExists(const std::string& f) { return target_->FileExists(f); }
Status GetChildren(const std::string& dir, std::vector<std::string>* r) {
return target_->GetChildren(dir, r);
diff --git a/src/leveldb/include/leveldb/iterator.h b/src/leveldb/include/leveldb/iterator.h
index 76aced04bd..da631ed9d8 100644
--- a/src/leveldb/include/leveldb/iterator.h
+++ b/src/leveldb/include/leveldb/iterator.h
@@ -37,7 +37,7 @@ class Iterator {
// Valid() after this call iff the source is not empty.
virtual void SeekToLast() = 0;
- // Position at the first key in the source that at or past target
+ // Position at the first key in the source that is at or past target.
// The iterator is Valid() after this call iff the source contains
// an entry that comes at or past target.
virtual void Seek(const Slice& target) = 0;
diff --git a/src/leveldb/include/leveldb/options.h b/src/leveldb/include/leveldb/options.h
index 7c9b973454..83a1ef39a4 100644
--- a/src/leveldb/include/leveldb/options.h
+++ b/src/leveldb/include/leveldb/options.h
@@ -128,6 +128,12 @@ struct Options {
// efficiently detect that and will switch to uncompressed mode.
CompressionType compression;
+ // EXPERIMENTAL: If true, append to existing MANIFEST and log files
+ // when a database is opened. This can significantly speed up open.
+ //
+ // Default: currently false, but may become true later.
+ bool reuse_logs;
+
// If non-NULL, use the specified filter policy to reduce disk reads.
// Many applications will benefit from passing the result of
// NewBloomFilterPolicy() here.
diff --git a/src/leveldb/include/leveldb/status.h b/src/leveldb/include/leveldb/status.h
index 11dbd4b47e..d9575f9753 100644
--- a/src/leveldb/include/leveldb/status.h
+++ b/src/leveldb/include/leveldb/status.h
@@ -60,6 +60,12 @@ class Status {
// Returns true iff the status indicates an IOError.
bool IsIOError() const { return code() == kIOError; }
+ // Returns true iff the status indicates a NotSupportedError.
+ bool IsNotSupportedError() const { return code() == kNotSupported; }
+
+ // Returns true iff the status indicates an InvalidArgument.
+ bool IsInvalidArgument() const { return code() == kInvalidArgument; }
+
// Return a string representation of this status suitable for printing.
// Returns the string "OK" for success.
std::string ToString() const;
diff --git a/src/leveldb/port/atomic_pointer.h b/src/leveldb/port/atomic_pointer.h
index 9bf091f757..1c4c7aafc6 100644
--- a/src/leveldb/port/atomic_pointer.h
+++ b/src/leveldb/port/atomic_pointer.h
@@ -35,8 +35,12 @@
#define ARCH_CPU_X86_FAMILY 1
#elif defined(__ARMEL__)
#define ARCH_CPU_ARM_FAMILY 1
+#elif defined(__aarch64__)
+#define ARCH_CPU_ARM64_FAMILY 1
#elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__)
#define ARCH_CPU_PPC_FAMILY 1
+#elif defined(__mips__)
+#define ARCH_CPU_MIPS_FAMILY 1
#endif
namespace leveldb {
@@ -92,6 +96,13 @@ inline void MemoryBarrier() {
}
#define LEVELDB_HAVE_MEMORY_BARRIER
+// ARM64
+#elif defined(ARCH_CPU_ARM64_FAMILY)
+inline void MemoryBarrier() {
+ asm volatile("dmb sy" : : : "memory");
+}
+#define LEVELDB_HAVE_MEMORY_BARRIER
+
// PPC
#elif defined(ARCH_CPU_PPC_FAMILY) && defined(__GNUC__)
inline void MemoryBarrier() {
@@ -101,6 +112,13 @@ inline void MemoryBarrier() {
}
#define LEVELDB_HAVE_MEMORY_BARRIER
+// MIPS
+#elif defined(ARCH_CPU_MIPS_FAMILY) && defined(__GNUC__)
+inline void MemoryBarrier() {
+ __asm__ __volatile__("sync" : : : "memory");
+}
+#define LEVELDB_HAVE_MEMORY_BARRIER
+
#endif
// AtomicPointer built using platform-specific MemoryBarrier()
@@ -215,6 +233,7 @@ class AtomicPointer {
#undef LEVELDB_HAVE_MEMORY_BARRIER
#undef ARCH_CPU_X86_FAMILY
#undef ARCH_CPU_ARM_FAMILY
+#undef ARCH_CPU_ARM64_FAMILY
#undef ARCH_CPU_PPC_FAMILY
} // namespace port
diff --git a/src/leveldb/port/port_posix.cc b/src/leveldb/port/port_posix.cc
index 5ba127a5b9..30e8007ae3 100644
--- a/src/leveldb/port/port_posix.cc
+++ b/src/leveldb/port/port_posix.cc
@@ -7,7 +7,6 @@
#include <cstdlib>
#include <stdio.h>
#include <string.h>
-#include "util/logging.h"
namespace leveldb {
namespace port {
diff --git a/src/leveldb/table/filter_block.cc b/src/leveldb/table/filter_block.cc
index 203e15c8bc..4e78b954f8 100644
--- a/src/leveldb/table/filter_block.cc
+++ b/src/leveldb/table/filter_block.cc
@@ -68,7 +68,7 @@ void FilterBlockBuilder::GenerateFilter() {
// Generate filter for current set of keys and append to result_.
filter_offsets_.push_back(result_.size());
- policy_->CreateFilter(&tmp_keys_[0], num_keys, &result_);
+ policy_->CreateFilter(&tmp_keys_[0], static_cast<int>(num_keys), &result_);
tmp_keys_.clear();
keys_.clear();
@@ -97,7 +97,7 @@ bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) {
if (index < num_) {
uint32_t start = DecodeFixed32(offset_ + index*4);
uint32_t limit = DecodeFixed32(offset_ + index*4 + 4);
- if (start <= limit && limit <= (offset_ - data_)) {
+ if (start <= limit && limit <= static_cast<size_t>(offset_ - data_)) {
Slice filter = Slice(data_ + start, limit - start);
return policy_->KeyMayMatch(key, filter);
} else if (start == limit) {
diff --git a/src/leveldb/table/format.cc b/src/leveldb/table/format.cc
index aa63144c9e..24e4e02445 100644
--- a/src/leveldb/table/format.cc
+++ b/src/leveldb/table/format.cc
@@ -30,15 +30,14 @@ Status BlockHandle::DecodeFrom(Slice* input) {
}
void Footer::EncodeTo(std::string* dst) const {
-#ifndef NDEBUG
const size_t original_size = dst->size();
-#endif
metaindex_handle_.EncodeTo(dst);
index_handle_.EncodeTo(dst);
dst->resize(2 * BlockHandle::kMaxEncodedLength); // Padding
PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber & 0xffffffffu));
PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber >> 32));
assert(dst->size() == original_size + kEncodedLength);
+ (void)original_size; // Disable unused variable warning.
}
Status Footer::DecodeFrom(Slice* input) {
diff --git a/src/leveldb/table/iterator_wrapper.h b/src/leveldb/table/iterator_wrapper.h
index 9e16b3dbed..f410c3fabe 100644
--- a/src/leveldb/table/iterator_wrapper.h
+++ b/src/leveldb/table/iterator_wrapper.h
@@ -5,6 +5,9 @@
#ifndef STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_
#define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_
+#include "leveldb/iterator.h"
+#include "leveldb/slice.h"
+
namespace leveldb {
// A internal wrapper class with an interface similar to Iterator that
diff --git a/src/leveldb/table/table.cc b/src/leveldb/table/table.cc
index dff8a82590..decf8082cc 100644
--- a/src/leveldb/table/table.cc
+++ b/src/leveldb/table/table.cc
@@ -82,7 +82,7 @@ Status Table::Open(const Options& options,
*table = new Table(rep);
(*table)->ReadMeta(footer);
} else {
- if (index_block) delete index_block;
+ delete index_block;
}
return s;
diff --git a/src/leveldb/table/table_test.cc b/src/leveldb/table/table_test.cc
index c723bf84cf..abf6e246ff 100644
--- a/src/leveldb/table/table_test.cc
+++ b/src/leveldb/table/table_test.cc
@@ -853,12 +853,20 @@ TEST(TableTest, ApproximateOffsetOfCompressed) {
options.compression = kSnappyCompression;
c.Finish(options, &keys, &kvmap);
- ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0));
- ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0));
- ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0));
- ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 2000, 3000));
- ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 2000, 3000));
- ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 4000, 6000));
+ // Expected upper and lower bounds of space used by compressible strings.
+ static const int kSlop = 1000; // Compressor effectiveness varies.
+ const int expected = 2500; // 10000 * compression ratio (0.25)
+ const int min_z = expected - kSlop;
+ const int max_z = expected + kSlop;
+
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, kSlop));
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, kSlop));
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, kSlop));
+ // Have now emitted a large compressible string, so adjust expected offset.
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), min_z, max_z));
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), min_z, max_z));
+ // Have now emitted two large compressible strings, so adjust expected offset.
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 2 * min_z, 2 * max_z));
}
} // namespace leveldb
diff --git a/src/leveldb/util/arena.cc b/src/leveldb/util/arena.cc
index 9367f71492..74078213ee 100644
--- a/src/leveldb/util/arena.cc
+++ b/src/leveldb/util/arena.cc
@@ -9,8 +9,7 @@ namespace leveldb {
static const int kBlockSize = 4096;
-Arena::Arena() {
- blocks_memory_ = 0;
+Arena::Arena() : memory_usage_(0) {
alloc_ptr_ = NULL; // First allocation will allocate a block
alloc_bytes_remaining_ = 0;
}
@@ -60,8 +59,9 @@ char* Arena::AllocateAligned(size_t bytes) {
char* Arena::AllocateNewBlock(size_t block_bytes) {
char* result = new char[block_bytes];
- blocks_memory_ += block_bytes;
blocks_.push_back(result);
+ memory_usage_.NoBarrier_Store(
+ reinterpret_cast<void*>(MemoryUsage() + block_bytes + sizeof(char*)));
return result;
}
diff --git a/src/leveldb/util/arena.h b/src/leveldb/util/arena.h
index 73bbf1cb9b..48bab33741 100644
--- a/src/leveldb/util/arena.h
+++ b/src/leveldb/util/arena.h
@@ -9,6 +9,7 @@
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
+#include "port/port.h"
namespace leveldb {
@@ -24,10 +25,9 @@ class Arena {
char* AllocateAligned(size_t bytes);
// Returns an estimate of the total memory usage of data allocated
- // by the arena (including space allocated but not yet used for user
- // allocations).
+ // by the arena.
size_t MemoryUsage() const {
- return blocks_memory_ + blocks_.capacity() * sizeof(char*);
+ return reinterpret_cast<uintptr_t>(memory_usage_.NoBarrier_Load());
}
private:
@@ -41,8 +41,8 @@ class Arena {
// Array of new[] allocated memory blocks
std::vector<char*> blocks_;
- // Bytes of memory in blocks allocated so far
- size_t blocks_memory_;
+ // Total memory usage of the arena.
+ port::AtomicPointer memory_usage_;
// No copying allowed
Arena(const Arena&);
diff --git a/src/leveldb/util/bloom.cc b/src/leveldb/util/bloom.cc
index a27a2ace28..bf3e4ca6e9 100644
--- a/src/leveldb/util/bloom.cc
+++ b/src/leveldb/util/bloom.cc
@@ -47,7 +47,7 @@ class BloomFilterPolicy : public FilterPolicy {
dst->resize(init_size + bytes, 0);
dst->push_back(static_cast<char>(k_)); // Remember # of probes in filter
char* array = &(*dst)[init_size];
- for (size_t i = 0; i < n; i++) {
+ for (int i = 0; i < n; i++) {
// Use double-hashing to generate a sequence of hash values.
// See analysis in [Kirsch,Mitzenmacher 2006].
uint32_t h = BloomHash(keys[i]);
diff --git a/src/leveldb/util/bloom_test.cc b/src/leveldb/util/bloom_test.cc
index 77fb1b3159..1b87a2be3f 100644
--- a/src/leveldb/util/bloom_test.cc
+++ b/src/leveldb/util/bloom_test.cc
@@ -46,7 +46,8 @@ class BloomTest {
key_slices.push_back(Slice(keys_[i]));
}
filter_.clear();
- policy_->CreateFilter(&key_slices[0], key_slices.size(), &filter_);
+ policy_->CreateFilter(&key_slices[0], static_cast<int>(key_slices.size()),
+ &filter_);
keys_.clear();
if (kVerbose >= 2) DumpFilter();
}
diff --git a/src/leveldb/util/cache.cc b/src/leveldb/util/cache.cc
index 8b197bc02a..ce46886171 100644
--- a/src/leveldb/util/cache.cc
+++ b/src/leveldb/util/cache.cc
@@ -19,6 +19,23 @@ Cache::~Cache() {
namespace {
// LRU cache implementation
+//
+// Cache entries have an "in_cache" boolean indicating whether the cache has a
+// reference on the entry. The only ways that this can become false without the
+// entry being passed to its "deleter" are via Erase(), via Insert() when
+// an element with a duplicate key is inserted, or on destruction of the cache.
+//
+// The cache keeps two linked lists of items in the cache. All items in the
+// cache are in one list or the other, and never both. Items still referenced
+// by clients but erased from the cache are in neither list. The lists are:
+// - in-use: contains the items currently referenced by clients, in no
+// particular order. (This list is used for invariant checking. If we
+// removed the check, elements that would otherwise be on this list could be
+// left as disconnected singleton lists.)
+// - LRU: contains the items not currently referenced by clients, in LRU order
+// Elements are moved between these lists by the Ref() and Unref() methods,
+// when they detect an element in the cache acquiring or losing its only
+// external reference.
// An entry is a variable length heap-allocated structure. Entries
// are kept in a circular doubly linked list ordered by access time.
@@ -30,7 +47,8 @@ struct LRUHandle {
LRUHandle* prev;
size_t charge; // TODO(opt): Only allow uint32_t?
size_t key_length;
- uint32_t refs;
+ bool in_cache; // Whether entry is in the cache.
+ uint32_t refs; // References, including cache reference, if present.
uint32_t hash; // Hash of key(); used for fast sharding and comparisons
char key_data[1]; // Beginning of key
@@ -147,49 +165,77 @@ class LRUCache {
Cache::Handle* Lookup(const Slice& key, uint32_t hash);
void Release(Cache::Handle* handle);
void Erase(const Slice& key, uint32_t hash);
+ void Prune();
+ size_t TotalCharge() const {
+ MutexLock l(&mutex_);
+ return usage_;
+ }
private:
void LRU_Remove(LRUHandle* e);
- void LRU_Append(LRUHandle* e);
+ void LRU_Append(LRUHandle*list, LRUHandle* e);
+ void Ref(LRUHandle* e);
void Unref(LRUHandle* e);
+ bool FinishErase(LRUHandle* e);
// Initialized before use.
size_t capacity_;
// mutex_ protects the following state.
- port::Mutex mutex_;
+ mutable port::Mutex mutex_;
size_t usage_;
// Dummy head of LRU list.
// lru.prev is newest entry, lru.next is oldest entry.
+ // Entries have refs==1 and in_cache==true.
LRUHandle lru_;
+ // Dummy head of in-use list.
+ // Entries are in use by clients, and have refs >= 2 and in_cache==true.
+ LRUHandle in_use_;
+
HandleTable table_;
};
LRUCache::LRUCache()
: usage_(0) {
- // Make empty circular linked list
+ // Make empty circular linked lists.
lru_.next = &lru_;
lru_.prev = &lru_;
+ in_use_.next = &in_use_;
+ in_use_.prev = &in_use_;
}
LRUCache::~LRUCache() {
+ assert(in_use_.next == &in_use_); // Error if caller has an unreleased handle
for (LRUHandle* e = lru_.next; e != &lru_; ) {
LRUHandle* next = e->next;
- assert(e->refs == 1); // Error if caller has an unreleased handle
+ assert(e->in_cache);
+ e->in_cache = false;
+ assert(e->refs == 1); // Invariant of lru_ list.
Unref(e);
e = next;
}
}
+void LRUCache::Ref(LRUHandle* e) {
+ if (e->refs == 1 && e->in_cache) { // If on lru_ list, move to in_use_ list.
+ LRU_Remove(e);
+ LRU_Append(&in_use_, e);
+ }
+ e->refs++;
+}
+
void LRUCache::Unref(LRUHandle* e) {
assert(e->refs > 0);
e->refs--;
- if (e->refs <= 0) {
- usage_ -= e->charge;
+ if (e->refs == 0) { // Deallocate.
+ assert(!e->in_cache);
(*e->deleter)(e->key(), e->value);
free(e);
+ } else if (e->in_cache && e->refs == 1) { // No longer in use; move to lru_ list.
+ LRU_Remove(e);
+ LRU_Append(&lru_, e);
}
}
@@ -198,10 +244,10 @@ void LRUCache::LRU_Remove(LRUHandle* e) {
e->prev->next = e->next;
}
-void LRUCache::LRU_Append(LRUHandle* e) {
- // Make "e" newest entry by inserting just before lru_
- e->next = &lru_;
- e->prev = lru_.prev;
+void LRUCache::LRU_Append(LRUHandle* list, LRUHandle* e) {
+ // Make "e" newest entry by inserting just before *list
+ e->next = list;
+ e->prev = list->prev;
e->prev->next = e;
e->next->prev = e;
}
@@ -210,9 +256,7 @@ Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) {
MutexLock l(&mutex_);
LRUHandle* e = table_.Lookup(key, hash);
if (e != NULL) {
- e->refs++;
- LRU_Remove(e);
- LRU_Append(e);
+ Ref(e);
}
return reinterpret_cast<Cache::Handle*>(e);
}
@@ -234,34 +278,58 @@ Cache::Handle* LRUCache::Insert(
e->charge = charge;
e->key_length = key.size();
e->hash = hash;
- e->refs = 2; // One from LRUCache, one for the returned handle
+ e->in_cache = false;
+ e->refs = 1; // for the returned handle.
memcpy(e->key_data, key.data(), key.size());
- LRU_Append(e);
- usage_ += charge;
- LRUHandle* old = table_.Insert(e);
- if (old != NULL) {
- LRU_Remove(old);
- Unref(old);
- }
+ if (capacity_ > 0) {
+ e->refs++; // for the cache's reference.
+ e->in_cache = true;
+ LRU_Append(&in_use_, e);
+ usage_ += charge;
+ FinishErase(table_.Insert(e));
+ } // else don't cache. (Tests use capacity_==0 to turn off caching.)
while (usage_ > capacity_ && lru_.next != &lru_) {
LRUHandle* old = lru_.next;
- LRU_Remove(old);
- table_.Remove(old->key(), old->hash);
- Unref(old);
+ assert(old->refs == 1);
+ bool erased = FinishErase(table_.Remove(old->key(), old->hash));
+ if (!erased) { // to avoid unused variable when compiled NDEBUG
+ assert(erased);
+ }
}
return reinterpret_cast<Cache::Handle*>(e);
}
-void LRUCache::Erase(const Slice& key, uint32_t hash) {
- MutexLock l(&mutex_);
- LRUHandle* e = table_.Remove(key, hash);
+// If e != NULL, finish removing *e from the cache; it has already been removed
+// from the hash table. Return whether e != NULL. Requires mutex_ held.
+bool LRUCache::FinishErase(LRUHandle* e) {
if (e != NULL) {
+ assert(e->in_cache);
LRU_Remove(e);
+ e->in_cache = false;
+ usage_ -= e->charge;
Unref(e);
}
+ return e != NULL;
+}
+
+void LRUCache::Erase(const Slice& key, uint32_t hash) {
+ MutexLock l(&mutex_);
+ FinishErase(table_.Remove(key, hash));
+}
+
+void LRUCache::Prune() {
+ MutexLock l(&mutex_);
+ while (lru_.next != &lru_) {
+ LRUHandle* e = lru_.next;
+ assert(e->refs == 1);
+ bool erased = FinishErase(table_.Remove(e->key(), e->hash));
+ if (!erased) { // to avoid unused variable when compiled NDEBUG
+ assert(erased);
+ }
+ }
}
static const int kNumShardBits = 4;
@@ -314,6 +382,18 @@ class ShardedLRUCache : public Cache {
MutexLock l(&id_mutex_);
return ++(last_id_);
}
+ virtual void Prune() {
+ for (int s = 0; s < kNumShards; s++) {
+ shard_[s].Prune();
+ }
+ }
+ virtual size_t TotalCharge() const {
+ size_t total = 0;
+ for (int s = 0; s < kNumShards; s++) {
+ total += shard_[s].TotalCharge();
+ }
+ return total;
+ }
};
} // end anonymous namespace
diff --git a/src/leveldb/util/cache_test.cc b/src/leveldb/util/cache_test.cc
index 43716715a8..468f7a6425 100644
--- a/src/leveldb/util/cache_test.cc
+++ b/src/leveldb/util/cache_test.cc
@@ -59,6 +59,11 @@ class CacheTest {
&CacheTest::Deleter));
}
+ Cache::Handle* InsertAndReturnHandle(int key, int value, int charge = 1) {
+ return cache_->Insert(EncodeKey(key), EncodeValue(value), charge,
+ &CacheTest::Deleter);
+ }
+
void Erase(int key) {
cache_->Erase(EncodeKey(key));
}
@@ -135,8 +140,11 @@ TEST(CacheTest, EntriesArePinned) {
TEST(CacheTest, EvictionPolicy) {
Insert(100, 101);
Insert(200, 201);
+ Insert(300, 301);
+ Cache::Handle* h = cache_->Lookup(EncodeKey(300));
- // Frequently used entry must be kept around
+ // Frequently used entry must be kept around,
+ // as must things that are still in use.
for (int i = 0; i < kCacheSize + 100; i++) {
Insert(1000+i, 2000+i);
ASSERT_EQ(2000+i, Lookup(1000+i));
@@ -144,6 +152,25 @@ TEST(CacheTest, EvictionPolicy) {
}
ASSERT_EQ(101, Lookup(100));
ASSERT_EQ(-1, Lookup(200));
+ ASSERT_EQ(301, Lookup(300));
+ cache_->Release(h);
+}
+
+TEST(CacheTest, UseExceedsCacheSize) {
+ // Overfill the cache, keeping handles on all inserted entries.
+ std::vector<Cache::Handle*> h;
+ for (int i = 0; i < kCacheSize + 100; i++) {
+ h.push_back(InsertAndReturnHandle(1000+i, 2000+i));
+ }
+
+ // Check that all the entries can be found in the cache.
+ for (int i = 0; i < h.size(); i++) {
+ ASSERT_EQ(2000+i, Lookup(1000+i));
+ }
+
+ for (int i = 0; i < h.size(); i++) {
+ cache_->Release(h[i]);
+ }
}
TEST(CacheTest, HeavyEntries) {
@@ -179,6 +206,19 @@ TEST(CacheTest, NewId) {
ASSERT_NE(a, b);
}
+TEST(CacheTest, Prune) {
+ Insert(1, 100);
+ Insert(2, 200);
+
+ Cache::Handle* handle = cache_->Lookup(EncodeKey(1));
+ ASSERT_TRUE(handle);
+ cache_->Prune();
+ cache_->Release(handle);
+
+ ASSERT_EQ(100, Lookup(1));
+ ASSERT_EQ(-1, Lookup(2));
+}
+
} // namespace leveldb
int main(int argc, char** argv) {
diff --git a/src/leveldb/util/env.cc b/src/leveldb/util/env.cc
index c2600e964a..c58a0821ef 100644
--- a/src/leveldb/util/env.cc
+++ b/src/leveldb/util/env.cc
@@ -9,6 +9,10 @@ namespace leveldb {
Env::~Env() {
}
+Status Env::NewAppendableFile(const std::string& fname, WritableFile** result) {
+ return Status::NotSupported("NewAppendableFile", fname);
+}
+
SequentialFile::~SequentialFile() {
}
diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc
index ba2667864a..e0fca52f46 100644
--- a/src/leveldb/util/env_posix.cc
+++ b/src/leveldb/util/env_posix.cc
@@ -351,6 +351,19 @@ class PosixEnv : public Env {
return s;
}
+ virtual Status NewAppendableFile(const std::string& fname,
+ WritableFile** result) {
+ Status s;
+ FILE* f = fopen(fname.c_str(), "a");
+ if (f == NULL) {
+ *result = NULL;
+ s = IOError(fname, errno);
+ } else {
+ *result = new PosixWritableFile(fname, f);
+ }
+ return s;
+ }
+
virtual bool FileExists(const std::string& fname) {
return access(fname.c_str(), F_OK) == 0;
}
diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc
index e11a96b791..b074b7579e 100644
--- a/src/leveldb/util/env_win.cc
+++ b/src/leveldb/util/env_win.cc
@@ -106,7 +106,7 @@ private:
class Win32WritableFile : public WritableFile
{
public:
- Win32WritableFile(const std::string& fname);
+ Win32WritableFile(const std::string& fname, bool append);
~Win32WritableFile();
virtual Status Append(const Slice& data);
@@ -158,6 +158,8 @@ public:
RandomAccessFile** result);
virtual Status NewWritableFile(const std::string& fname,
WritableFile** result);
+ virtual Status NewAppendableFile(const std::string& fname,
+ WritableFile** result);
virtual bool FileExists(const std::string& fname);
@@ -423,17 +425,23 @@ void Win32RandomAccessFile::_CleanUp()
}
}
-Win32WritableFile::Win32WritableFile(const std::string& fname)
+Win32WritableFile::Win32WritableFile(const std::string& fname, bool append)
: filename_(fname)
{
std::wstring path;
ToWidePath(fname, path);
- DWORD Flag = PathFileExistsW(path.c_str()) ? OPEN_EXISTING : CREATE_ALWAYS;
+ // NewAppendableFile: append to an existing file, or create a new one
+ // if none exists - this is OPEN_ALWAYS behavior, with
+ // FILE_APPEND_DATA to avoid having to manually position the file
+ // pointer at the end of the file.
+ // NewWritableFile: create a new file, delete if it exists - this is
+ // CREATE_ALWAYS behavior. This file is used for writing only so
+ // use GENERIC_WRITE.
_hFile = CreateFileW(path.c_str(),
- GENERIC_READ | GENERIC_WRITE,
+ append ? FILE_APPEND_DATA : GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
NULL,
- Flag,
+ append ? OPEN_ALWAYS : CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
// CreateFileW returns INVALID_HANDLE_VALUE in case of error, always check isEnable() before use
@@ -823,7 +831,9 @@ Status Win32Env::NewLogger( const std::string& fname, Logger** result )
{
Status sRet;
std::string path = fname;
- Win32WritableFile* pMapFile = new Win32WritableFile(ModifyPath(path));
+ // Logs are opened with write semantics, not with append semantics
+ // (see PosixEnv::NewLogger)
+ Win32WritableFile* pMapFile = new Win32WritableFile(ModifyPath(path), false);
if(!pMapFile->isEnable()){
delete pMapFile;
*result = NULL;
@@ -837,7 +847,20 @@ Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** resul
{
Status sRet;
std::string path = fname;
- Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path));
+ Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path), false);
+ if(!pFile->isEnable()){
+ *result = NULL;
+ sRet = Status::IOError(fname,Win32::GetLastErrSz());
+ }else
+ *result = pFile;
+ return sRet;
+}
+
+Status Win32Env::NewAppendableFile( const std::string& fname, WritableFile** result )
+{
+ Status sRet;
+ std::string path = fname;
+ Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path), true);
if(!pFile->isEnable()){
*result = NULL;
sRet = Status::IOError(fname,Win32::GetLastErrSz());
diff --git a/src/leveldb/util/options.cc b/src/leveldb/util/options.cc
index 76af5b9302..8b618fb1ae 100644
--- a/src/leveldb/util/options.cc
+++ b/src/leveldb/util/options.cc
@@ -22,8 +22,8 @@ Options::Options()
block_size(4096),
block_restart_interval(16),
compression(kSnappyCompression),
+ reuse_logs(false),
filter_policy(NULL) {
}
-
} // namespace leveldb
diff --git a/src/leveldb/util/testutil.h b/src/leveldb/util/testutil.h
index adad3fc1ea..d7e4583702 100644
--- a/src/leveldb/util/testutil.h
+++ b/src/leveldb/util/testutil.h
@@ -45,6 +45,16 @@ class ErrorEnv : public EnvWrapper {
}
return target()->NewWritableFile(fname, result);
}
+
+ virtual Status NewAppendableFile(const std::string& fname,
+ WritableFile** result) {
+ if (writable_file_error_) {
+ ++num_writable_file_errors_;
+ *result = NULL;
+ return Status::IOError(fname, "fake error");
+ }
+ return target()->NewAppendableFile(fname, result);
+ }
};
} // namespace test
diff --git a/src/limitedmap.h b/src/limitedmap.h
index 4d9bb4fa21..e9dcb6defd 100644
--- a/src/limitedmap.h
+++ b/src/limitedmap.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -66,8 +66,11 @@ public:
}
void update(const_iterator itIn, const mapped_type& v)
{
- // TODO: When we switch to C++11, use map.erase(itIn, itIn) to get the non-const iterator.
- iterator itTarget = map.find(itIn->first);
+ // Using map::erase() with empty range instead of map::find() to get a non-const iterator,
+ // since it is a constant time operation in C++11. For more details, see
+ // https://stackoverflow.com/questions/765148/how-to-remove-constness-of-const-iterator
+ iterator itTarget = map.erase(itIn, itIn);
+
if (itTarget == map.end())
return;
std::pair<rmap_iterator, rmap_iterator> itPair = rmap.equal_range(itTarget->second);
diff --git a/src/memusage.h b/src/memusage.h
index 3810bfad07..b69acafffd 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin developers
+// Copyright (c) 2015-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.
@@ -12,6 +12,8 @@
#include <map>
#include <set>
#include <vector>
+#include <unordered_map>
+#include <unordered_set>
#include <boost/foreach.hpp>
#include <boost/unordered_set.hpp>
@@ -149,7 +151,7 @@ static inline size_t DynamicUsage(const std::shared_ptr<X>& p)
// Boost data structures
template<typename X>
-struct boost_unordered_node : private X
+struct unordered_node : private X
{
private:
void* ptr;
@@ -158,13 +160,25 @@ private:
template<typename X, typename Y>
static inline size_t DynamicUsage(const boost::unordered_set<X, Y>& s)
{
- return MallocUsage(sizeof(boost_unordered_node<X>)) * s.size() + MallocUsage(sizeof(void*) * s.bucket_count());
+ 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)
{
- 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());
+}
+
+template<typename X, typename Y>
+static inline size_t DynamicUsage(const std::unordered_set<X, Y>& s)
+{
+ 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 std::unordered_map<X, Y, Z>& m)
+{
+ 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 31332526a9..78d7cd6001 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -9,25 +9,23 @@
#include "consensus/consensus.h"
#include "utilstrencodings.h"
-using namespace std;
-
CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
{
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());
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
- const uint256& hash = block.vtx[i].GetHash();
- if (filter.IsRelevantAndUpdate(block.vtx[i]))
+ const uint256& hash = block.vtx[i]->GetHash();
+ if (filter.IsRelevantAndUpdate(*block.vtx[i]))
{
vMatch.push_back(true);
- vMatchedTxn.push_back(make_pair(i, hash));
+ vMatchedTxn.push_back(std::make_pair(i, hash));
}
else
vMatch.push_back(false);
@@ -41,15 +39,15 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, 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());
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
- const uint256& hash = block.vtx[i].GetHash();
+ const uint256& hash = block.vtx[i]->GetHash();
if (txids.count(hash))
vMatch.push_back(true);
else
@@ -67,7 +65,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve
} 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
diff --git a/src/merkleblock.h b/src/merkleblock.h
index 835cbcce55..de4c5c8d29 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -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.
@@ -85,7 +85,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nTransactions);
READWRITE(vHash);
std::vector<unsigned char> vBytes;
@@ -148,7 +148,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(header);
READWRITE(txn);
}
diff --git a/src/miner.cpp b/src/miner.cpp
index 8153fb9f9e..9d2959723a 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -13,8 +13,9 @@
#include "consensus/merkle.h"
#include "consensus/validation.h"
#include "hash.h"
-#include "main.h"
+#include "validation.h"
#include "net.h"
+#include "policy/feerate.h"
#include "policy/policy.h"
#include "pow.h"
#include "primitives/transaction.h"
@@ -26,11 +27,8 @@
#include "validationinterface.h"
#include <algorithm>
-#include <boost/thread.hpp>
-#include <boost/tuple/tuple.hpp>
#include <queue>
-
-using namespace std;
+#include <utility>
//////////////////////////////////////////////////////////////////////////////
//
@@ -40,23 +38,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 nLastBlockCost = 0;
-
-class ScoreCompare
-{
-public:
- ScoreCompare() {}
-
- bool operator()(const CTxMemPool::txiter a, const CTxMemPool::txiter b)
- {
- return CompareTxMemPoolEntryByScore()(*b,*a); // Convert to less than
- }
-};
+uint64_t nLastBlockWeight = 0;
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
@@ -73,67 +60,85 @@ 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;
+ nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
+}
+
+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));
+ // Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity:
+ nBlockMaxSize = std::max<size_t>(1000, std::min<size_t>(MAX_BLOCK_SERIALIZED_SIZE - 1000, options.nBlockMaxSize));
+ // Whether we need to account for byte usage (in addition to weight usage)
+ fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE - 1000);
+}
+
+static BlockAssembler::Options DefaultOptions(const CChainParams& params)
{
// Block resource limits
- // If neither -blockmaxsize or -blockmaxcost is given, limit to DEFAULT_BLOCK_MAX_*
+ // 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.
- nBlockMaxCost = DEFAULT_BLOCK_MAX_COST;
- nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
- bool fCostSet = false;
- if (mapArgs.count("-blockmaxcost")) {
- nBlockMaxCost = GetArg("-blockmaxcost", DEFAULT_BLOCK_MAX_COST);
- nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
- fCostSet = true;
+ BlockAssembler::Options options;
+ options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
+ options.nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
+ bool fWeightSet = false;
+ if (IsArgSet("-blockmaxweight")) {
+ options.nBlockMaxWeight = GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
+ options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
+ fWeightSet = true;
}
- if (mapArgs.count("-blockmaxsize")) {
- nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
- if (!fCostSet) {
- nBlockMaxCost = nBlockMaxSize * WITNESS_SCALE_FACTOR;
+ if (IsArgSet("-blockmaxsize")) {
+ options.nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
+ if (!fWeightSet) {
+ options.nBlockMaxWeight = options.nBlockMaxSize * WITNESS_SCALE_FACTOR;
}
}
-
- // Limit cost to between 4K and MAX_BLOCK_COST-4K for sanity:
- nBlockMaxCost = std::max((unsigned int)4000, std::min((unsigned int)(MAX_BLOCK_COST-4000), nBlockMaxCost));
- // 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 cost usage)
- fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE-1000);
+ if (IsArgSet("-blockmintxfee")) {
+ CAmount n = 0;
+ ParseMoney(GetArg("-blockmintxfee", ""), n);
+ options.blockMinFeeRate = CFeeRate(n);
+ } else {
+ options.blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
+ }
+ return options;
}
+BlockAssembler::BlockAssembler(const CChainParams& params) : BlockAssembler(params, DefaultOptions(params)) {}
+
void BlockAssembler::resetBlock()
{
inBlock.clear();
// Reserve space for coinbase tx
nBlockSize = 1000;
- nBlockCost = 4000;
+ nBlockWeight = 4000;
nBlockSigOpsCost = 400;
fIncludeWitness = false;
// These counters do not include coinbase tx
nBlockTx = 0;
nFees = 0;
-
- lastFewTxs = 0;
- blockFinished = false;
}
-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());
if(!pblocktemplate.get())
- return NULL;
+ return nullptr;
pblock = &pblocktemplate->block; // pointer for convenience
// Add dummy coinbase tx as first transaction
- pblock->vtx.push_back(CTransaction());
+ pblock->vtx.emplace_back();
pblocktemplate->vTxFees.push_back(-1); // updated at end
pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end
@@ -160,15 +165,17 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
// -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;
- nLastBlockCost = nBlockCost;
- LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOpsCost);
+ nLastBlockWeight = nBlockWeight;
// Create coinbase transaction.
CMutableTransaction coinbaseTx;
@@ -178,34 +185,29 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
- pblock->vtx[0] = coinbaseTx;
+ pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
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);
+
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
pblock->nNonce = 0;
- pblocktemplate->vTxSigOpsCost[0] = GetLegacySigOpCount(pblock->vtx[0]);
+ pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
CValidationState state;
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 pblocktemplate.release();
-}
+ 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)
@@ -223,8 +225,8 @@ void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)
bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost)
{
- // TODO: switch to cost-based accounting for packages instead of vsize-based accounting.
- if (nBlockCost + WITNESS_SCALE_FACTOR * packageSize >= nBlockMaxCost)
+ // TODO: switch to weight-based accounting for packages instead of vsize-based accounting.
+ if (nBlockWeight + WITNESS_SCALE_FACTOR * packageSize >= nBlockMaxWeight)
return false;
if (nBlockSigOpsCost + packageSigOpsCost >= MAX_BLOCK_SIGOPS_COST)
return false;
@@ -242,7 +244,7 @@ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& packa
BOOST_FOREACH (const CTxMemPool::txiter it, package) {
if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff))
return false;
- if (!fIncludeWitness && !it->GetTx().wit.IsNull())
+ if (!fIncludeWitness && it->GetTx().HasWitness())
return false;
if (fNeedSizeAccounting) {
uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
@@ -255,67 +257,15 @@ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& packa
return true;
}
-bool BlockAssembler::TestForBlock(CTxMemPool::txiter iter)
-{
- if (nBlockCost + iter->GetTxCost() >= nBlockMaxCost) {
- // 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 (nBlockCost > nBlockMaxCost - 400 || lastFewTxs > 50) {
- blockFinished = true;
- return false;
- }
- // Once we're within 4000 cost of a full block, only look at 50 more txs
- // to try to fill the remaining space.
- if (nBlockCost > nBlockMaxCost - 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;
-}
-
void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
{
- pblock->vtx.push_back(iter->GetTx());
+ 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);
}
- nBlockCost += iter->GetTxCost();
+ nBlockWeight += iter->GetTxWeight();
++nBlockTx;
nBlockSigOpsCost += iter->GetSigOpCost();
nFees += iter->GetFee();
@@ -323,19 +273,16 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
bool fPrintPriority = 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)
{
+ int nDescendantsUpdated = 0;
BOOST_FOREACH(const CTxMemPool::txiter it, alreadyAdded) {
CTxMemPool::setEntries descendants;
mempool.CalculateDescendants(it, descendants);
@@ -343,6 +290,7 @@ void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alread
BOOST_FOREACH(CTxMemPool::txiter desc, descendants) {
if (alreadyAdded.count(desc))
continue;
+ ++nDescendantsUpdated;
modtxiter mit = mapModifiedTx.find(desc);
if (mit == mapModifiedTx.end()) {
CTxMemPoolModifiedEntry modEntry(desc);
@@ -355,6 +303,7 @@ void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alread
}
}
}
+ return nDescendantsUpdated;
}
// Skip entries in mapTx that are already in a block or are present
@@ -369,9 +318,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)
@@ -395,7 +342,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
@@ -409,6 +356,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.
@@ -457,7 +411,7 @@ void BlockAssembler::addPackageTxs()
packageSigOpsCost = modit->nSigOpCostWithAncestors;
}
- if (packageFees < ::minRelayTxFee.GetFee(packageSize)) {
+ if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
// Everything else we might consider has a lower fee rate
return;
}
@@ -470,6 +424,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;
}
@@ -490,8 +452,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) {
@@ -500,91 +465,11 @@ void BlockAssembler::addPackageTxs()
mapModifiedTx.erase(sortedEntries[i]);
}
- // Update transactions that depend on each of these
- UpdatePackagesForAdded(ancestors, mapModifiedTx);
- }
-}
-
-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;
- }
+ ++nPackagesSelected;
- 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().wit.IsNull())
- 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)
@@ -598,10 +483,10 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
}
++nExtraNonce;
unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
- CMutableTransaction txCoinbase(pblock->vtx[0]);
+ CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
assert(txCoinbase.vin[0].scriptSig.size() <= 100);
- pblock->vtx[0] = txCoinbase;
+ pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
}
diff --git a/src/miner.h b/src/miner.h
index d16e37bb59..1f3c9d652f 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -141,11 +141,12 @@ private:
// Configuration parameters for the block size
bool fIncludeWitness;
- unsigned int nBlockMaxCost, nBlockMaxSize;
+ unsigned int nBlockMaxWeight, nBlockMaxSize;
bool fNeedSizeAccounting;
+ CFeeRate blockMinFeeRate;
// Information on the current status of the block
- uint64_t nBlockCost;
+ uint64_t nBlockWeight;
uint64_t nBlockSize;
uint64_t nBlockTx;
uint64_t nBlockSigOpsCost;
@@ -157,14 +158,19 @@ 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;
+ size_t nBlockMaxSize;
+ CFeeRate blockMinFeeRate;
+ };
+
+ BlockAssembler(const CChainParams& params);
+ BlockAssembler(const CChainParams& params, const Options& options);
+
/** Construct a new block template with coinbase to scriptPubKeyIn */
- CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn);
+ std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx=true);
private:
// utility functions
@@ -174,16 +180,10 @@ 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 */
@@ -201,8 +201,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 4cbc43e4d8..dd375e580f 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -17,6 +17,7 @@
#include "crypto/sha256.h"
#include "hash.h"
#include "primitives/transaction.h"
+#include "netbase.h"
#include "scheduler.h"
#include "ui_interface.h"
#include "utilstrencodings.h"
@@ -34,18 +35,24 @@
#include <miniupnpc/upnperrors.h>
#endif
-#include <boost/filesystem.hpp>
-#include <boost/thread.hpp>
#include <math.h>
// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
#define DUMP_ADDRESSES_INTERVAL 900
-#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
+// 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)
#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
@@ -57,62 +64,28 @@
#endif
#endif
-
-namespace {
- const int MAX_OUTBOUND_CONNECTIONS = 8;
-
- struct ListenSocket {
- SOCKET socket;
- bool whitelisted;
-
- ListenSocket(SOCKET socket, bool whitelisted) : socket(socket), whitelisted(whitelisted) {}
- };
-}
-
const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
-/** Services this node implementation cares about */
-ServiceFlags nRelevantServices = NODE_NETWORK;
-
+static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
+static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
//
// Global state variables
//
bool fDiscover = true;
bool fListen = true;
-ServiceFlags nLocalServices = NODE_NETWORK;
bool fRelayTxes = true;
CCriticalSection cs_mapLocalHost;
std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfLimited[NET_MAX] = {};
-static CNode* pnodeLocalHost = NULL;
-uint64_t nLocalHostNonce = 0;
-static std::vector<ListenSocket> vhListenSocket;
-CAddrMan addrman;
-int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
-bool fAddressesInitialized = false;
std::string strSubVersion;
-std::vector<CNode*> vNodes;
-CCriticalSection cs_vNodes;
limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
-static std::deque<std::string> vOneShots;
-CCriticalSection cs_vOneShots;
-
-std::vector<std::string> vAddedNodes;
-CCriticalSection cs_vAddedNodes;
-
-NodeId nLastNodeId = 0;
-CCriticalSection cs_nLastNodeId;
-
-static CSemaphore *semOutbound = NULL;
-boost::condition_variable messageHandlerCondition;
-
// Signals for message handling
static CNodeSignals g_signals;
CNodeSignals& GetNodeSignals() { return g_signals; }
-void AddOneShot(const std::string& strDest)
+void CConnman::AddOneShot(const std::string& strDest)
{
LOCK(cs_vOneShots);
vOneShots.push_back(strDest);
@@ -173,9 +146,9 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn
// Otherwise, return the unroutable 0.0.0.0 but filled in with
// the normal parameters, since the IP may be changed to a useful
// one by discovery.
-CAddress GetLocalAddress(const CNetAddr *paddrPeer)
+CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
{
- CAddress ret(CService("0.0.0.0",GetListenPort()), NODE_NONE);
+ CAddress ret(CService(CNetAddr(),GetListenPort()), NODE_NONE);
CService addr;
if (GetLocal(addr, paddrPeer))
{
@@ -196,8 +169,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
@@ -205,19 +179,20 @@ void AdvertiseLocal(CNode *pnode)
{
if (fListen && pnode->fSuccessfullyConnected)
{
- CAddress addrLocal = GetLocalAddress(&pnode->addr);
+ CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices());
// If discovery is enabled, sometimes give our peer the address it
// tells us that it sees us as in case it has a better idea of our
// address than we do.
if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0))
{
- addrLocal.SetIP(pnode->addrLocal);
+ addrLocal.SetIP(pnode->GetAddrLocal());
}
if (addrLocal.IsRoutable())
{
- LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
- pnode->PushAddress(addrLocal);
+ LogPrint(BCLog::NET, "AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
+ FastRandomContext insecure_rand;
+ pnode->PushAddress(addrLocal, insecure_rand);
}
}
}
@@ -316,23 +291,8 @@ bool IsReachable(const CNetAddr& addr)
return IsReachable(net);
}
-void AddressCurrentlyConnected(const CService& addr)
-{
- addrman.Connected(addr);
-}
-
-
-uint64_t CNode::nTotalBytesRecv = 0;
-uint64_t CNode::nTotalBytesSent = 0;
-CCriticalSection CNode::cs_totalBytesRecv;
-CCriticalSection CNode::cs_totalBytesSent;
-
-uint64_t CNode::nMaxOutboundLimit = 0;
-uint64_t CNode::nMaxOutboundTotalBytesSentInCycle = 0;
-uint64_t CNode::nMaxOutboundTimeframe = 60*60*24; //1 day
-uint64_t CNode::nMaxOutboundCycleStartTime = 0;
-CNode* FindNode(const CNetAddr& ip)
+CNode* CConnman::FindNode(const CNetAddr& ip)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -341,7 +301,7 @@ CNode* FindNode(const CNetAddr& ip)
return NULL;
}
-CNode* FindNode(const CSubNet& subNet)
+CNode* CConnman::FindNode(const CSubNet& subNet)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -350,16 +310,18 @@ CNode* FindNode(const CSubNet& subNet)
return NULL;
}
-CNode* FindNode(const std::string& addrName)
+CNode* CConnman::FindNode(const std::string& addrName)
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->addrName == addrName)
+ BOOST_FOREACH(CNode* pnode, vNodes) {
+ if (pnode->GetAddrName() == addrName) {
return (pnode);
+ }
+ }
return NULL;
}
-CNode* FindNode(const CService& addr)
+CNode* CConnman::FindNode(const CService& addr)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -368,17 +330,17 @@ CNode* FindNode(const CService& addr)
return NULL;
}
-//TODO: This is used in only one place in main, and should be removed
-CNode* FindNode(const NodeId nodeid)
+bool CConnman::CheckIncomingNonce(uint64_t nonce)
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->GetId() == nodeid)
- return (pnode);
- return NULL;
+ BOOST_FOREACH(CNode* pnode, vNodes) {
+ if (!pnode->fSuccessfullyConnected && !pnode->fInbound && pnode->GetLocalNonce() == nonce)
+ return false;
+ }
+ return true;
}
-CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)
+CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)
{
if (pszDest == NULL) {
if (IsLocal(addrConnect))
@@ -388,13 +350,13 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure
CNode* pnode = FindNode((CService)addrConnect);
if (pnode)
{
- pnode->AddRef();
- return pnode;
+ LogPrintf("Failed to open new connection, already connected\n");
+ return NULL;
}
}
/// 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);
@@ -415,34 +377,25 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure
// 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);
- }
- }
+ pnode->MaybeSetAddrName(std::string(pszDest));
CloseSocket(hSocket);
- return pnode;
+ LogPrintf("Failed to open new connection, already connected\n");
+ return NULL;
}
}
addrman.Attempt(addrConnect, fCountFailure);
// Add node
- CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
- pnode->AddRef();
-
- {
- LOCK(cs_vNodes);
- vNodes.push_back(pnode);
- }
-
+ 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);
pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
- pnode->nTimeConnected = GetTime();
+ pnode->AddRef();
return pnode;
} else if (!proxyConnectionFailed) {
@@ -454,66 +407,38 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure
return NULL;
}
-static void DumpBanlist()
+void CConnman::DumpBanlist()
{
- CNode::SweepBanned(); // clean unused entries (if bantime has expired)
+ SweepBanned(); // clean unused entries (if bantime has expired)
- if (!CNode::BannedSetIsDirty())
+ if (!BannedSetIsDirty())
return;
int64_t nStart = GetTimeMillis();
CBanDB bandb;
banmap_t banmap;
- CNode::SetBannedSetDirty(false);
- CNode::GetBanned(banmap);
- if (!bandb.Write(banmap))
- CNode::SetBannedSetDirty(true);
+ GetBanned(banmap);
+ 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);
}
-
- // in case this fails, we'll empty the recv buffer when the CNode is deleted
- TRY_LOCK(cs_vRecvMsg, lockRecv);
- if (lockRecv)
- vRecvMsg.clear();
}
-void CNode::PushVersion()
-{
- int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0);
-
- int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
- CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", 0), addr.nServices));
- CAddress addrMe = GetLocalAddress(&addr);
- GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
- if (fLogIPs)
- LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id);
- else
- LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
- PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalServices, nTime, addrYou, addrMe,
- nLocalHostNonce, strSubVersion, nBestHeight, ::fRelayTxes);
-}
-
-
-
-
-
-banmap_t CNode::setBanned;
-CCriticalSection CNode::cs_setBanned;
-bool CNode::setBannedIsDirty;
-
-void CNode::ClearBanned()
+void CConnman::ClearBanned()
{
{
LOCK(cs_setBanned);
@@ -521,10 +446,11 @@ void CNode::ClearBanned()
setBannedIsDirty = true;
}
DumpBanlist(); //store banlist to disk
- uiInterface.BannedListChanged();
+ if(clientInterface)
+ clientInterface->BannedListChanged();
}
-bool CNode::IsBanned(CNetAddr ip)
+bool CConnman::IsBanned(CNetAddr ip)
{
bool fResult = false;
{
@@ -541,7 +467,7 @@ bool CNode::IsBanned(CNetAddr ip)
return fResult;
}
-bool CNode::IsBanned(CSubNet subnet)
+bool CConnman::IsBanned(CSubNet subnet)
{
bool fResult = false;
{
@@ -557,12 +483,12 @@ bool CNode::IsBanned(CSubNet subnet)
return fResult;
}
-void CNode::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
+void CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
CSubNet subNet(addr);
Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
}
-void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
+void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
CBanEntry banEntry(GetTime());
banEntry.banReason = banReason;
if (bantimeoffset <= 0)
@@ -581,7 +507,8 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti
else
return;
}
- uiInterface.BannedListChanged();
+ if(clientInterface)
+ clientInterface->BannedListChanged();
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) {
@@ -593,37 +520,40 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti
DumpBanlist(); //store banlist to disk immediately if user requested ban
}
-bool CNode::Unban(const CNetAddr &addr) {
+bool CConnman::Unban(const CNetAddr &addr) {
CSubNet subNet(addr);
return Unban(subNet);
}
-bool CNode::Unban(const CSubNet &subNet) {
+bool CConnman::Unban(const CSubNet &subNet) {
{
LOCK(cs_setBanned);
if (!setBanned.erase(subNet))
return false;
setBannedIsDirty = true;
}
- uiInterface.BannedListChanged();
+ if(clientInterface)
+ clientInterface->BannedListChanged();
DumpBanlist(); //store banlist to disk immediately
return true;
}
-void CNode::GetBanned(banmap_t &banMap)
+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
}
-void CNode::SetBanned(const banmap_t &banMap)
+void CConnman::SetBanned(const banmap_t &banMap)
{
LOCK(cs_setBanned);
setBanned = banMap;
setBannedIsDirty = true;
}
-void CNode::SweepBanned()
+void CConnman::SweepBanned()
{
int64_t now = GetTime();
@@ -637,30 +567,27 @@ void CNode::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;
}
}
-bool CNode::BannedSetIsDirty()
+bool CConnman::BannedSetIsDirty()
{
LOCK(cs_setBanned);
return setBannedIsDirty;
}
-void CNode::SetBannedSetDirty(bool dirty)
+void CConnman::SetBannedSetDirty(bool dirty)
{
LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag
setBannedIsDirty = dirty;
}
-std::vector<CSubNet> CNode::vWhitelistedRange;
-CCriticalSection CNode::cs_vWhitelistedRange;
-
-bool CNode::IsWhitelistedRange(const CNetAddr &addr) {
+bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
LOCK(cs_vWhitelistedRange);
BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) {
if (subnet.Match(addr))
@@ -669,31 +596,72 @@ bool CNode::IsWhitelistedRange(const CNetAddr &addr) {
return false;
}
-void CNode::AddWhitelistedRange(const CSubNet &subnet) {
+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
#define X(name) stats.name = name
void CNode::copyStats(CNodeStats &stats)
{
stats.nodeid = this->GetId();
X(nServices);
- X(fRelayTxes);
+ X(addr);
+ {
+ 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,
@@ -709,23 +677,28 @@ void CNode::copyStats(CNodeStats &stats)
// Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :)
stats.dPingTime = (((double)nPingUsecTime) / 1e6);
- stats.dPingMin = (((double)nMinPingUsecTime) / 1e6);
+ stats.dMinPing = (((double)nMinPingUsecTime) / 1e6);
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
-// requires LOCK(cs_vRecvMsg)
-bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
+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) {
// get current incomplete message, or create a new one
if (vRecvMsg.empty() ||
vRecvMsg.back().complete())
- vRecvMsg.push_back(CNetMessage(Params().MessageStart(), SER_NETWORK, nRecvVersion));
+ vRecvMsg.push_back(CNetMessage(Params().MessageStart(), SER_NETWORK, INIT_PROTO_VERSION));
CNetMessage& msg = vRecvMsg.back();
@@ -737,10 +710,10 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
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;
}
@@ -757,14 +730,41 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
assert(i != mapRecvBytesPerMsgCmd.end());
i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
- msg.nTime = GetTimeMicros();
- messageHandlerCondition.notify_one();
+ msg.nTime = nTimeMicros;
+ complete = true;
}
}
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
@@ -788,7 +788,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;
@@ -806,12 +806,21 @@ int CNetMessage::readData(const char *pch, unsigned int nBytes)
vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));
}
+ hasher.Write((const unsigned char*)pch, nCopy);
memcpy(&vRecv[nDataPos], pch, nCopy);
nDataPos += nCopy;
return nCopy;
}
+const uint256& CNetMessage::GetMessageHash() const
+{
+ assert(complete());
+ if (data_hash.IsNull())
+ hasher.Finalize(data_hash.begin());
+ return data_hash;
+}
+
@@ -821,22 +830,30 @@ int CNetMessage::readData(const char *pch, unsigned int nBytes)
// requires LOCK(cs_vSend)
-void SocketSendData(CNode *pnode)
+size_t CConnman::SocketSendData(CNode *pnode) const
{
- std::deque<CSerializeData>::iterator it = pnode->vSendMsg.begin();
+ auto it = pnode->vSendMsg.begin();
+ size_t nSentSize = 0;
while (it != pnode->vSendMsg.end()) {
- const CSerializeData &data = *it;
+ const auto &data = *it;
assert(data.size() > pnode->nSendOffset);
- int nBytes = send(pnode->hSocket, &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;
- pnode->RecordBytesSent(nBytes);
+ nSentSize += nBytes;
if (pnode->nSendOffset == data.size()) {
pnode->nSendOffset = 0;
pnode->nSendSize -= data.size();
+ pnode->fPauseSend = pnode->nSendSize > nSendBufferMaxSize;
it++;
} else {
// could not send full message; stop sending more
@@ -862,10 +879,9 @@ void SocketSendData(CNode *pnode)
assert(pnode->nSendSize == 0);
}
pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it);
+ return nSentSize;
}
-static std::list<CNode*> vNodesDisconnected;
-
struct NodeEvictionCandidate
{
NodeId id;
@@ -873,7 +889,7 @@ struct NodeEvictionCandidate
int64_t nMinPingUsecTime;
int64_t nLastBlockTime;
int64_t nLastTXTime;
- bool fNetworkNode;
+ bool fRelevantServices;
bool fRelayTxes;
bool fBloomFilter;
CAddress addr;
@@ -898,7 +914,7 @@ static bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvict
{
// There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block.
if (a.nLastBlockTime != b.nLastBlockTime) return a.nLastBlockTime < b.nLastBlockTime;
- if (a.fNetworkNode != b.fNetworkNode) return b.fNetworkNode;
+ if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices;
return a.nTimeConnected > b.nTimeConnected;
}
@@ -919,7 +935,8 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction
* to forge. In order to partition a node the attacker must be
* simultaneously better at all of them than honest peers.
*/
-static bool AttemptToEvictConnection() {
+bool CConnman::AttemptToEvictConnection()
+{
std::vector<NodeEvictionCandidate> vEvictionCandidates;
{
LOCK(cs_vNodes);
@@ -931,8 +948,9 @@ static bool AttemptToEvictConnection() {
continue;
if (node->fDisconnect)
continue;
- NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime,
- node->nLastBlockTime, node->nLastTXTime, node->fNetworkNode,
+ 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};
vEvictionCandidates.push_back(candidate);
}
@@ -982,11 +1000,11 @@ static bool AttemptToEvictConnection() {
uint64_t naMostConnections;
unsigned int nMostConnections = 0;
int64_t nMostConnectionsTime = 0;
- std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapAddrCounts;
+ std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) {
- mapAddrCounts[node.nKeyedNetGroup].push_back(node);
- int64_t grouptime = mapAddrCounts[node.nKeyedNetGroup][0].nTimeConnected;
- size_t groupsize = mapAddrCounts[node.nKeyedNetGroup].size();
+ mapNetGroupNodes[node.nKeyedNetGroup].push_back(node);
+ int64_t grouptime = mapNetGroupNodes[node.nKeyedNetGroup][0].nTimeConnected;
+ size_t groupsize = mapNetGroupNodes[node.nKeyedNetGroup].size();
if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {
nMostConnections = groupsize;
@@ -996,7 +1014,7 @@ static bool AttemptToEvictConnection() {
}
// Reduce to the network group with the most connections
- vEvictionCandidates = std::move(mapAddrCounts[naMostConnections]);
+ vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]);
// Disconnect from the network group with the most connections
NodeId evicted = vEvictionCandidates.front().id;
@@ -1010,19 +1028,19 @@ static bool AttemptToEvictConnection() {
return false;
}
-static void AcceptConnection(const ListenSocket& hListenSocket) {
+void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
CAddress addr;
int nInbound = 0;
- int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS;
+ int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler);
if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
LogPrintf("Warning: Unknown socket family\n");
- bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr);
+ bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr);
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -1038,6 +1056,12 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
return;
}
+ if (!fNetworkActive) {
+ LogPrintf("connection from %s dropped: not accepting new connections\n", addr.ToString());
+ CloseSocket(hSocket);
+ return;
+ }
+
if (!IsSelectableSocket(hSocket))
{
LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString());
@@ -1054,7 +1078,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
#endif
- if (CNode::IsBanned(addr) && !whitelisted)
+ if (IsBanned(addr) && !whitelisted)
{
LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
CloseSocket(hSocket);
@@ -1065,17 +1089,21 @@ static void 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;
}
}
- CNode* pnode = new CNode(hSocket, addr, "", true);
+ NodeId id = GetNewNodeId();
+ uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
+
+ CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, "", true);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
+ GetNodeSignals().InitializeNode(pnode, *this);
- LogPrint("net", "connection from %s accepted\n", addr.ToString());
+ LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
{
LOCK(cs_vNodes);
@@ -1083,10 +1111,10 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
}
}
-void ThreadSocketHandler()
+void CConnman::ThreadSocketHandler()
{
unsigned int nPrevNodeCount = 0;
- while (true)
+ while (!interruptNet)
{
//
// Disconnect nodes
@@ -1097,8 +1125,7 @@ void ThreadSocketHandler()
std::vector<CNode*> vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
- if (pnode->fDisconnect ||
- (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty()))
+ if (pnode->fDisconnect)
{
// remove from vNodes
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
@@ -1110,8 +1137,7 @@ void ThreadSocketHandler()
pnode->CloseSocketDisconnect();
// hold in disconnected pool until all refs are released
- if (pnode->fNetworkNode || pnode->fInbound)
- pnode->Release();
+ pnode->Release();
vNodesDisconnected.push_back(pnode);
}
}
@@ -1122,33 +1148,33 @@ void ThreadSocketHandler()
BOOST_FOREACH(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_vRecvMsg, lockRecv);
- if (lockRecv)
- {
- 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);
- delete pnode;
+ DeleteNode(pnode);
}
}
}
}
- if(vNodes.size() != nPrevNodeCount) {
- nPrevNodeCount = vNodes.size();
- uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount);
+ size_t vNodesSize;
+ {
+ LOCK(cs_vNodes);
+ vNodesSize = vNodes.size();
+ }
+ if(vNodesSize != nPrevNodeCount) {
+ nPrevNodeCount = vNodesSize;
+ if(clientInterface)
+ clientInterface->NotifyNumConnectionsChanged(nPrevNodeCount);
}
//
@@ -1177,47 +1203,46 @@ void ThreadSocketHandler()
LOCK(cs_vNodes);
BOOST_FOREACH(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
// write buffer in this case before receiving more. This avoids
// needlessly queueing received data, if the remote peer is not themselves
// receiving data. This means properly utilizing TCP flow control signalling.
- // * Otherwise, if there is no (complete) message in the receive buffer,
- // or there is space left in the buffer, select() for receiving data.
- // * (if neither of the above applies, there is certainly one message
- // in the receiver buffer ready to be processed).
- // Together, that means that at least one of the following is always possible,
- // so we don't deadlock:
- // * We send some data.
- // * We wait for data to be received (and disconnect after timeout).
- // * We process a message in the buffer (message handler thread).
+ // * Otherwise, if there is space left in the receive buffer, select() for
+ // 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 && !pnode->vSendMsg.empty()) {
- FD_SET(pnode->hSocket, &fdsetSend);
- continue;
- }
+ LOCK(pnode->cs_vSend);
+ select_send = !pnode->vSendMsg.empty();
}
- {
- TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
- if (lockRecv && (
- pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() ||
- pnode->GetTotalRecvSize() <= ReceiveFloodSize()))
- 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);
}
}
}
int nSelect = select(have_fds ? hSocketMax + 1 : 0,
&fdsetRecv, &fdsetSend, &fdsetError, &timeout);
- boost::this_thread::interruption_point();
+ if (interruptNet)
+ return;
if (nSelect == SOCKET_ERROR)
{
@@ -1230,7 +1255,8 @@ void ThreadSocketHandler()
}
FD_ZERO(&fdsetSend);
FD_ZERO(&fdsetError);
- MilliSleep(timeout.tv_usec/1000);
+ if (!interruptNet.sleep_for(std::chrono::milliseconds(timeout.tv_usec/1000)))
+ return;
}
//
@@ -1256,48 +1282,74 @@ void ThreadSocketHandler()
}
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
- boost::this_thread::interruption_point();
+ if (interruptNet)
+ return;
//
// 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)
{
- TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
- if (lockRecv)
+ // 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)
- {
- if (!pnode->ReceiveMsgBytes(pchBuf, nBytes))
- pnode->CloseSocketDisconnect();
- pnode->nLastRecv = GetTime();
- pnode->nRecvBytes += nBytes;
- pnode->RecordBytesRecv(nBytes);
- }
- 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();
}
}
}
@@ -1305,24 +1357,24 @@ void ThreadSocketHandler()
//
// Send
//
- if (pnode->hSocket == INVALID_SOCKET)
- continue;
- if (FD_ISSET(pnode->hSocket, &fdsetSend))
+ if (sendSet)
{
- TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend)
- SocketSendData(pnode);
+ 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)
@@ -1340,6 +1392,11 @@ void 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;
+ }
}
}
{
@@ -1350,8 +1407,14 @@ void ThreadSocketHandler()
}
}
-
-
+void CConnman::WakeMessageHandler()
+{
+ {
+ std::lock_guard<std::mutex> lock(mutexMsgProc);
+ fMsgProcWake = true;
+ }
+ condMsgProc.notify_one();
+}
@@ -1396,8 +1459,11 @@ void ThreadMapPort()
{
if(externalIPAddress[0])
{
- LogPrintf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
- AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP);
+ CNetAddr resolved;
+ if(LookupHost(externalIPAddress, resolved, false)) {
+ LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString().c_str());
+ AddLocal(resolved, LOCAL_UPNP);
+ }
}
else
LogPrintf("UPnP: GetExternalIPAddress failed.\n");
@@ -1484,19 +1550,28 @@ static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredSe
return data.host;
}
+ // See chainparams.cpp, most dnsseeds only support one or two possible servicebits hostnames
return strprintf("x%x.%s", *requiredServiceBits, data.host);
}
-void ThreadDNSAddressSeed()
+void CConnman::ThreadDNSAddressSeed()
{
// goal: only query DNS seeds if address need is acute
+ // Avoiding DNS seeds when we don't need them improves user privacy by
+ // 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))) {
- MilliSleep(11 * 1000);
+ if (!interruptNet.sleep_for(std::chrono::seconds(11)))
+ return;
LOCK(cs_vNodes);
- if (vNodes.size() >= 2) {
+ int nRelevant = 0;
+ for (auto pnode : vNodes) {
+ nRelevant += pnode->fSuccessfullyConnected && ((pnode->nServices & nRelevantServices) == nRelevantServices);
+ }
+ if (nRelevant >= 2) {
LogPrintf("P2P peers available. Skipped DNS seeding.\n");
return;
}
@@ -1508,6 +1583,9 @@ void ThreadDNSAddressSeed()
LogPrintf("Loading addresses from DNS seeds (could take a while)\n");
BOOST_FOREACH(const CDNSSeedData &seed, vSeeds) {
+ if (interruptNet) {
+ return;
+ }
if (HaveNameProxy()) {
AddOneShot(seed.host);
} else {
@@ -1525,6 +1603,9 @@ void ThreadDNSAddressSeed()
found++;
}
}
+ if (interruptNet) {
+ return;
+ }
// 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
@@ -1551,24 +1632,24 @@ void ThreadDNSAddressSeed()
-void DumpAddresses()
+void CConnman::DumpAddresses()
{
int64_t nStart = GetTimeMillis();
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);
}
-void DumpData()
+void CConnman::DumpData()
{
DumpAddresses();
DumpBanlist();
}
-void static ProcessOneShot()
+void CConnman::ProcessOneShot()
{
std::string strDest;
{
@@ -1586,44 +1667,53 @@ void static ProcessOneShot()
}
}
-void ThreadOpenConnections()
+void CConnman::ThreadOpenConnections()
{
// Connect to specific addresses
- if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0)
+ if (gArgs.IsArgSet("-connect") && gArgs.GetArgs("-connect").size() > 0)
{
for (int64_t nLoop = 0;; nLoop++)
{
ProcessOneShot();
- BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"])
+ BOOST_FOREACH(const std::string& strAddr, gArgs.GetArgs("-connect"))
{
CAddress addr(CService(), NODE_NONE);
OpenNetworkConnection(addr, false, NULL, strAddr.c_str());
for (int i = 0; i < 10 && i < nLoop; i++)
{
- MilliSleep(500);
+ if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
+ return;
}
}
- MilliSleep(500);
+ if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
+ return;
}
}
// Initiate network connections
int64_t nStart = GetTime();
- while (true)
+
+ // Minimum time before next feeler connection (in microseconds).
+ int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);
+ while (!interruptNet)
{
ProcessOneShot();
- MilliSleep(500);
+ if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
+ return;
CSemaphoreGrant grant(*semOutbound);
- boost::this_thread::interruption_point();
+ if (interruptNet)
+ return;
// Add seed nodes if DNS seeds are all down (an infrastructure attack?).
if (addrman.size() == 0 && (GetTime() - nStart > 60)) {
static bool done = false;
if (!done) {
LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n");
- addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1"));
+ CNetAddr local;
+ LookupHost("127.0.0.1", local, false);
+ addrman.Add(convertSeed6(Params().FixedSeeds()), local);
done = true;
}
}
@@ -1640,19 +1730,46 @@ void ThreadOpenConnections()
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) {
- if (!pnode->fInbound) {
+ if (!pnode->fInbound && !pnode->fAddnode) {
+ // 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
+ // also have the added issue that they're attacker controlled and could be used
+ // to prevent us from connecting to particular hosts if we used them here.
setConnected.insert(pnode->addr.GetGroup());
nOutbound++;
}
}
}
- int64_t nANow = GetAdjustedTime();
+ // Feeler Connections
+ //
+ // Design goals:
+ // * 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
+ // successfully it is added to tried.
+ // * Start attempting feeler connections only after node finishes making outbound
+ // connections.
+ // * Only make a feeler connection once every few minutes.
+ //
+ bool fFeeler = false;
+ if (nOutbound >= nMaxOutbound) {
+ int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
+ if (nTime > nNextFeeler) {
+ nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
+ fFeeler = true;
+ } else {
+ continue;
+ }
+ }
+ int64_t nANow = GetAdjustedTime();
int nTries = 0;
- while (true)
+ while (!interruptNet)
{
- CAddrInfo addr = addrman.Select();
+ CAddrInfo addr = addrman.Select(fFeeler);
// if we selected an invalid address, restart
if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
@@ -1676,8 +1793,8 @@ void ThreadOpenConnections()
if (nANow - addr.nLastTry < 600 && nTries < 30)
continue;
- // only consider nodes missing relevant services after 40 failed attemps
- if ((addr.nServices & nRelevantServices) != nRelevantServices && nTries < 40)
+ // 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)))
continue;
// do not allow non-default ports, unless after 50 invalid addresses selected already
@@ -1688,12 +1805,22 @@ void ThreadOpenConnections()
break;
}
- if (addrConnect.IsValid())
- OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant);
+ if (addrConnect.IsValid()) {
+
+ if (fFeeler) {
+ // Add small amount of random noise before connection to avoid synchronization.
+ int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
+ if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep)))
+ return;
+ 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);
+ }
}
}
-std::vector<AddedNodeInfo> GetAddedNodeInfo()
+std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
{
std::vector<AddedNodeInfo> ret;
@@ -1715,14 +1842,15 @@ std::vector<AddedNodeInfo> 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) {
- CService service(strAddNode, Params().GetDefaultPort());
+ CService service(LookupNumeric(strAddNode.c_str(), Params().GetDefaultPort()));
if (service.IsValid()) {
// strAddNode is an IP:port
auto it = mapConnected.find(service);
@@ -1745,67 +1873,86 @@ std::vector<AddedNodeInfo> GetAddedNodeInfo()
return ret;
}
-void ThreadOpenAddedConnections()
+void CConnman::ThreadOpenAddedConnections()
{
{
LOCK(cs_vAddedNodes);
- vAddedNodes = mapMultiArgs["-addnode"];
+ if (gArgs.IsArgSet("-addnode"))
+ vAddedNodes = gArgs.GetArgs("-addnode");
}
- for (unsigned int i = 0; true; i++)
+ while (true)
{
+ CSemaphoreGrant grant(*semAddnode);
std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
+ bool tried = false;
for (const AddedNodeInfo& info : vInfo) {
if (!info.fConnected) {
- CSemaphoreGrant grant(*semOutbound);
+ if (!grant.TryAcquire()) {
+ // If we've used up our semaphore and need a new one, lets not wait here since while we are waiting
+ // 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.
- CService service(info.strAddedNode, Params().GetDefaultPort());
- OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false);
- MilliSleep(500);
+ 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);
+ if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
+ return;
}
}
-
- MilliSleep(120000); // Retry every 2 minutes
+ // Retry every 60 seconds if a connection was attempted, otherwise two seconds
+ if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2)))
+ return;
}
}
// if successful, this moves the passed grant to the constructed node
-bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
+bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool fAddnode)
{
//
// Initiate outbound network connection
//
- boost::this_thread::interruption_point();
+ if (interruptNet) {
+ return false;
+ }
+ if (!fNetworkActive) {
+ return false;
+ }
if (!pszDest) {
if (IsLocal(addrConnect) ||
- FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
+ FindNode((CNetAddr)addrConnect) || IsBanned(addrConnect) ||
FindNode(addrConnect.ToStringIPPort()))
return false;
} else if (FindNode(std::string(pszDest)))
return false;
CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure);
- boost::this_thread::interruption_point();
if (!pnode)
return false;
if (grantOutbound)
grantOutbound->MoveTo(pnode->grantOutbound);
- pnode->fNetworkNode = true;
if (fOneShot)
pnode->fOneShot = true;
+ if (fFeeler)
+ pnode->fFeeler = true;
+ if (fAddnode)
+ pnode->fAddnode = true;
+
+ GetNodeSignals().InitializeNode(pnode, *this);
+ {
+ LOCK(cs_vNodes);
+ vNodes.push_back(pnode);
+ }
return true;
}
-
-void ThreadMessageHandler()
+void CConnman::ThreadMessageHandler()
{
- boost::mutex condition_mutex;
- boost::unique_lock<boost::mutex> lock(condition_mutex);
-
- while (true)
+ while (!flagInterruptMsgProc)
{
std::vector<CNode*> vNodesCopy;
{
@@ -1816,7 +1963,7 @@ void ThreadMessageHandler()
}
}
- bool fSleep = true;
+ bool fMoreWork = false;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
@@ -1824,31 +1971,18 @@ void ThreadMessageHandler()
continue;
// Receive messages
- {
- TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
- if (lockRecv)
- {
- if (!GetNodeSignals().ProcessMessages(pnode))
- pnode->CloseSocketDisconnect();
-
- if (pnode->nSendSize < SendBufferSize())
- {
- if (!pnode->vRecvGetData.empty() || (!pnode->vRecvMsg.empty() && pnode->vRecvMsg[0].complete()))
- {
- fSleep = false;
- }
- }
- }
- }
- boost::this_thread::interruption_point();
+ bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc);
+ fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend);
+ if (flagInterruptMsgProc)
+ return;
// Send messages
{
- TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend)
- GetNodeSignals().SendMessages(pnode);
+ LOCK(pnode->cs_sendProcessing);
+ GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc);
}
- boost::this_thread::interruption_point();
+ if (flagInterruptMsgProc)
+ return;
}
{
@@ -1857,8 +1991,11 @@ void ThreadMessageHandler()
pnode->Release();
}
- if (fSleep)
- messageHandlerCondition.timed_wait(lock, boost::posix_time::microsec_clock::universal_time() + boost::posix_time::milliseconds(100));
+ std::unique_lock<std::mutex> lock(mutexMsgProc);
+ if (!fMoreWork) {
+ condMsgProc.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::milliseconds(100), [this] { return fMsgProcWake; });
+ }
+ fMsgProcWake = false;
}
}
@@ -1867,7 +2004,7 @@ void ThreadMessageHandler()
-bool BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted)
+bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted)
{
strError = "";
int nOne = 1;
@@ -1965,7 +2102,7 @@ bool BindListenPort(const CService &addrBind, std::string& strError, bool fWhite
return true;
}
-void static Discover(boost::thread_group& threadGroup)
+void Discover(boost::thread_group& threadGroup)
{
if (!fDiscover)
return;
@@ -2016,9 +2153,74 @@ void static Discover(boost::thread_group& threadGroup)
#endif
}
-void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
+void CConnman::SetNetworkActive(bool active)
+{
+ LogPrint(BCLog::NET, "SetNetworkActive: %s\n", active);
+
+ if (!active) {
+ fNetworkActive = false;
+
+ LOCK(cs_vNodes);
+ // Close sockets to all nodes
+ BOOST_FOREACH(CNode* pnode, vNodes) {
+ pnode->CloseSocketDisconnect();
+ }
+ } else {
+ fNetworkActive = true;
+ }
+
+ uiInterface.NotifyNetworkActiveChanged(fNetworkActive);
+}
+
+CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In)
+{
+ fNetworkActive = true;
+ setBannedIsDirty = false;
+ fAddressesInitialized = false;
+ nLastNodeId = 0;
+ nSendBufferMaxSize = 0;
+ nReceiveFloodSize = 0;
+ semOutbound = NULL;
+ semAddnode = NULL;
+ nMaxConnections = 0;
+ nMaxOutbound = 0;
+ nMaxAddnode = 0;
+ nBestHeight = 0;
+ clientInterface = NULL;
+ flagInterruptMsgProc = false;
+}
+
+NodeId CConnman::GetNewNodeId()
{
- uiInterface.InitMessage(_("Loading addresses..."));
+ return nLastNodeId.fetch_add(1, std::memory_order_relaxed);
+}
+
+bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options 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;
+
+ SetBestHeight(connOptions.nBestHeight);
+
+ clientInterface = connOptions.uiInterface;
+ if (clientInterface) {
+ clientInterface->InitMessage(_("Loading P2P addresses..."));
+ }
// Load addresses from peers.dat
int64_t nStart = GetTimeMillis();
{
@@ -2031,79 +2233,70 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
DumpAddresses();
}
}
-
- uiInterface.InitMessage(_("Loading banlist..."));
+ if (clientInterface)
+ clientInterface->InitMessage(_("Loading banlist..."));
// Load addresses from banlist.dat
nStart = GetTimeMillis();
CBanDB bandb;
banmap_t banmap;
if (bandb.Read(banmap)) {
- CNode::SetBanned(banmap); // thread save setter
- CNode::SetBannedSetDirty(false); // no need to write down, just read data
- CNode::SweepBanned(); // sweep out unused entries
+ SetBanned(banmap); // thread save setter
+ 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");
- CNode::SetBannedSetDirty(true); // force write
+ SetBannedSetDirty(true); // force write
DumpBanlist();
}
+ uiInterface.InitMessage(_("Starting network threads..."));
+
fAddressesInitialized = true;
if (semOutbound == NULL) {
// initialize semaphore
- int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections);
- semOutbound = new CSemaphore(nMaxOutbound);
+ semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
+ }
+ if (semAddnode == NULL) {
+ // initialize semaphore
+ semAddnode = new CSemaphore(nMaxAddnode);
}
-
- if (pnodeLocalHost == NULL)
- pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
-
- Discover(threadGroup);
//
// Start threads
//
+ InterruptSocks5(false);
+ interruptNet.reset();
+ flagInterruptMsgProc = false;
+
+ {
+ std::unique_lock<std::mutex> lock(mutexMsgProc);
+ fMsgProcWake = false;
+ }
+
+ // 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))
LogPrintf("DNS seeding disabled\n");
else
- threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "dnsseed", &ThreadDNSAddressSeed));
-
- // Map ports with UPnP
- MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
-
- // Send and receive from sockets, accept connections
- threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "net", &ThreadSocketHandler));
+ threadDNSAddressSeed = std::thread(&TraceThread<std::function<void()> >, "dnsseed", std::function<void()>(std::bind(&CConnman::ThreadDNSAddressSeed, this)));
// Initiate outbound connections from -addnode
- threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "addcon", &ThreadOpenAddedConnections));
+ threadOpenAddedConnections = std::thread(&TraceThread<std::function<void()> >, "addcon", std::function<void()>(std::bind(&CConnman::ThreadOpenAddedConnections, this)));
- // Initiate outbound connections
- threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "opencon", &ThreadOpenConnections));
+ // Initiate outbound connections unless connect=0
+ if (!gArgs.IsArgSet("-connect") || gArgs.GetArgs("-connect").size() != 1 || gArgs.GetArgs("-connect")[0] != "0")
+ threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this)));
// Process messages
- threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler));
+ threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this)));
// Dump network addresses
- scheduler.scheduleEvery(&DumpData, DUMP_ADDRESSES_INTERVAL);
-}
-
-bool StopNode()
-{
- LogPrintf("StopNode()\n");
- MapPort(false);
- if (semOutbound)
- for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
- semOutbound->post();
-
- if (fAddressesInitialized)
- {
- DumpData();
- fAddressesInitialized = false;
- }
+ scheduler.scheduleEvery(std::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL * 1000);
return true;
}
@@ -2115,28 +2308,6 @@ public:
~CNetCleanup()
{
- // Close sockets
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->hSocket != INVALID_SOCKET)
- CloseSocket(pnode->hSocket);
- BOOST_FOREACH(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)
- delete pnode;
- BOOST_FOREACH(CNode *pnode, vNodesDisconnected)
- delete pnode;
- vNodes.clear();
- vNodesDisconnected.clear();
- vhListenSocket.clear();
- delete semOutbound;
- semOutbound = NULL;
- delete pnodeLocalHost;
- pnodeLocalHost = NULL;
-
#ifdef WIN32
// Shutdown Windows Sockets
WSACleanup();
@@ -2145,24 +2316,192 @@ public:
}
instance_of_cnetcleanup;
+void CConnman::Interrupt()
+{
+ {
+ std::lock_guard<std::mutex> lock(mutexMsgProc);
+ flagInterruptMsgProc = true;
+ }
+ condMsgProc.notify_all();
+
+ interruptNet();
+ InterruptSocks5(true);
-void RelayTransaction(const CTransaction& tx)
+ 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()
{
- CInv inv(MSG_TX, tx.GetHash());
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
+ if (threadMessageHandler.joinable())
+ threadMessageHandler.join();
+ if (threadOpenConnections.joinable())
+ threadOpenConnections.join();
+ if (threadOpenAddedConnections.joinable())
+ threadOpenAddedConnections.join();
+ if (threadDNSAddressSeed.joinable())
+ threadDNSAddressSeed.join();
+ if (threadSocketHandler.joinable())
+ threadSocketHandler.join();
+
+ if (fAddressesInitialized)
{
- pnode->PushInventory(inv);
+ DumpData();
+ fAddressesInitialized = false;
+ }
+
+ // Close sockets
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ pnode->CloseSocketDisconnect();
+ BOOST_FOREACH(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) {
+ DeleteNode(pnode);
+ }
+ BOOST_FOREACH(CNode *pnode, vNodesDisconnected) {
+ DeleteNode(pnode);
+ }
+ vNodes.clear();
+ vNodesDisconnected.clear();
+ vhListenSocket.clear();
+ delete semOutbound;
+ semOutbound = NULL;
+ delete semAddnode;
+ semAddnode = NULL;
+}
+
+void CConnman::DeleteNode(CNode* pnode)
+{
+ assert(pnode);
+ bool fUpdateConnectionTime = false;
+ GetNodeSignals().FinalizeNode(pnode->GetId(), fUpdateConnectionTime);
+ if(fUpdateConnectionTime)
+ addrman.Connected(pnode->addr);
+ delete pnode;
+}
+
+CConnman::~CConnman()
+{
+ Interrupt();
+ Stop();
+}
+
+size_t CConnman::GetAddressCount() const
+{
+ return addrman.size();
+}
+
+void CConnman::SetServices(const CService &addr, ServiceFlags nServices)
+{
+ addrman.SetServices(addr, nServices);
+}
+
+void CConnman::MarkAddressGood(const CAddress& addr)
+{
+ addrman.Good(addr);
+}
+
+void CConnman::AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty)
+{
+ addrman.Add(vAddr, addrFrom, nTimePenalty);
+}
+
+std::vector<CAddress> CConnman::GetAddresses()
+{
+ return addrman.GetAddr();
+}
+
+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;
+ }
+
+ vAddedNodes.push_back(strNode);
+ return true;
+}
+
+bool CConnman::RemoveAddedNode(const std::string& strNode)
+{
+ LOCK(cs_vAddedNodes);
+ for(std::vector<std::string>::iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) {
+ if (strNode == *it) {
+ vAddedNodes.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
+size_t CConnman::GetNodeCount(NumConnections flags)
+{
+ LOCK(cs_vNodes);
+ if (flags == CConnman::CONNECTIONS_ALL) // Shortcut if we want total
+ 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))
+ nNum++;
+
+ return nNum;
+}
+
+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;
+ vstats.emplace_back();
+ pnode->copyStats(vstats.back());
+ }
+}
+
+bool CConnman::DisconnectNode(const std::string& strNode)
+{
+ LOCK(cs_vNodes);
+ if (CNode* pnode = FindNode(strNode)) {
+ pnode->fDisconnect = true;
+ return true;
+ }
+ return false;
+}
+bool CConnman::DisconnectNode(NodeId id)
+{
+ LOCK(cs_vNodes);
+ for(CNode* pnode : vNodes) {
+ if (id == pnode->GetId()) {
+ pnode->fDisconnect = true;
+ return true;
+ }
}
+ return false;
}
-void CNode::RecordBytesRecv(uint64_t bytes)
+void CConnman::RecordBytesRecv(uint64_t bytes)
{
LOCK(cs_totalBytesRecv);
nTotalBytesRecv += bytes;
}
-void CNode::RecordBytesSent(uint64_t bytes)
+void CConnman::RecordBytesSent(uint64_t bytes)
{
LOCK(cs_totalBytesSent);
nTotalBytesSent += bytes;
@@ -2179,29 +2518,25 @@ void CNode::RecordBytesSent(uint64_t bytes)
nMaxOutboundTotalBytesSentInCycle += bytes;
}
-void CNode::SetMaxOutboundTarget(uint64_t limit)
+void CConnman::SetMaxOutboundTarget(uint64_t limit)
{
LOCK(cs_totalBytesSent);
- uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SERIALIZED_SIZE;
nMaxOutboundLimit = limit;
-
- if (limit > 0 && limit < recommendedMinimum)
- LogPrintf("Max outbound target is very small (%s bytes) and will be overshot. Recommended minimum is %s bytes.\n", nMaxOutboundLimit, recommendedMinimum);
}
-uint64_t CNode::GetMaxOutboundTarget()
+uint64_t CConnman::GetMaxOutboundTarget()
{
LOCK(cs_totalBytesSent);
return nMaxOutboundLimit;
}
-uint64_t CNode::GetMaxOutboundTimeframe()
+uint64_t CConnman::GetMaxOutboundTimeframe()
{
LOCK(cs_totalBytesSent);
return nMaxOutboundTimeframe;
}
-uint64_t CNode::GetMaxOutboundTimeLeftInCycle()
+uint64_t CConnman::GetMaxOutboundTimeLeftInCycle()
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundLimit == 0)
@@ -2215,7 +2550,7 @@ uint64_t CNode::GetMaxOutboundTimeLeftInCycle()
return (cycleEndTime < now) ? 0 : cycleEndTime - GetTime();
}
-void CNode::SetMaxOutboundTimeframe(uint64_t timeframe)
+void CConnman::SetMaxOutboundTimeframe(uint64_t timeframe)
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundTimeframe != timeframe)
@@ -2227,7 +2562,7 @@ void CNode::SetMaxOutboundTimeframe(uint64_t timeframe)
nMaxOutboundTimeframe = timeframe;
}
-bool CNode::OutboundTargetReached(bool historicalBlockServingLimit)
+bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit)
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundLimit == 0)
@@ -2247,7 +2582,7 @@ bool CNode::OutboundTargetReached(bool historicalBlockServingLimit)
return false;
}
-uint64_t CNode::GetOutboundTargetBytesLeft()
+uint64_t CConnman::GetOutboundTargetBytesLeft()
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundLimit == 0)
@@ -2256,170 +2591,48 @@ uint64_t CNode::GetOutboundTargetBytesLeft()
return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle;
}
-uint64_t CNode::GetTotalBytesRecv()
+uint64_t CConnman::GetTotalBytesRecv()
{
LOCK(cs_totalBytesRecv);
return nTotalBytesRecv;
}
-uint64_t CNode::GetTotalBytesSent()
+uint64_t CConnman::GetTotalBytesSent()
{
LOCK(cs_totalBytesSent);
return nTotalBytesSent;
}
-void CNode::Fuzz(int nChance)
+ServiceFlags CConnman::GetLocalServices() const
{
- if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake
- if (GetRand(nChance) != 0) return; // Fuzz 1 of every nChance messages
-
- switch (GetRand(3))
- {
- case 0:
- // xor a random byte with a random value:
- if (!ssSend.empty()) {
- CDataStream::size_type pos = GetRand(ssSend.size());
- ssSend[pos] ^= (unsigned char)(GetRand(256));
- }
- break;
- case 1:
- // delete a random byte:
- if (!ssSend.empty()) {
- CDataStream::size_type pos = GetRand(ssSend.size());
- ssSend.erase(ssSend.begin()+pos);
- }
- break;
- case 2:
- // insert a random byte at a random position
- {
- CDataStream::size_type pos = GetRand(ssSend.size());
- char ch = (char)GetRand(256);
- ssSend.insert(ssSend.begin()+pos, ch);
- }
- break;
- }
- // Chance of more than one change half the time:
- // (more changes exponentially less likely):
- Fuzz(2);
+ return nLocalServices;
}
-//
-// CAddrDB
-//
-
-CAddrDB::CAddrDB()
+void CConnman::SetBestHeight(int height)
{
- pathAddr = GetDataDir() / "peers.dat";
+ nBestHeight.store(height, std::memory_order_release);
}
-bool CAddrDB::Write(const CAddrMan& addr)
+int CConnman::GetBestHeight() const
{
- // 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;
-
- // open temp output file, and associate with CAutoFile
- boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
- FILE *file = fopen(pathTmp.string().c_str(), "wb");
- CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
- if (fileout.IsNull())
- return error("%s: Failed to open file %s", __func__, pathTmp.string());
-
- // Write and commit header, data
- try {
- fileout << ssPeers;
- }
- catch (const std::exception& e) {
- return error("%s: Serialize or I/O error - %s", __func__, e.what());
- }
- FileCommit(fileout.Get());
- fileout.fclose();
-
- // replace existing peers.dat, if any, with new peers.dat.XXXX
- if (!RenameOver(pathTmp, pathAddr))
- return error("%s: Rename-into-place failed", __func__);
-
- return true;
-}
-
-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);
-}
-
-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
- addr.Clear();
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
- }
-
- return true;
+ return nBestHeight.load(std::memory_order_acquire);
}
-unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); }
-unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); }
+unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
+unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; }
-CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
- ssSend(SER_NETWORK, INIT_PROTO_VERSION),
+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) :
+ nTimeConnected(GetSystemTimeInSeconds()),
addr(addrIn),
- nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)),
+ fInbound(fInboundIn),
+ nKeyedNetGroup(nKeyedNetGroupIn),
addrKnown(5000, 0.001),
- filterInventoryKnown(50000, 0.000001)
+ filterInventoryKnown(50000, 0.000001),
+ id(idIn),
+ nLocalHostNonce(nLocalHostNonceIn),
+ nLocalServices(nLocalServicesIn),
+ nMyStartingHeight(nMyStartingHeightIn),
+ nSendVersion(0)
{
nServices = NODE_NONE;
nServicesExpected = NODE_NONE;
@@ -2429,16 +2642,15 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nLastRecv = 0;
nSendBytes = 0;
nRecvBytes = 0;
- nTimeConnected = GetTime();
nTimeOffset = 0;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0;
strSubVer = "";
fWhitelisted = false;
fOneShot = false;
+ fAddnode = false;
fClient = false; // set by version message
- fInbound = fInboundIn;
- fNetworkNode = false;
+ fFeeler = false;
fSuccessfullyConnected = false;
fDisconnect = false;
nRefCount = 0;
@@ -2466,26 +2678,19 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
minFeeFilter = 0;
lastSentFeeFilter = 0;
nextSendTimeFeeFilter = 0;
+ fPauseRecv = false;
+ fPauseSend = false;
+ nProcessQueueSize = 0;
BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
mapRecvBytesPerMsgCmd[msg] = 0;
mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
- {
- LOCK(cs_nLastNodeId);
- id = nLastNodeId++;
+ if (fLogIPs) {
+ LogPrint(BCLog::NET, "Added connection to %s peer=%d\n", addrName, id);
+ } else {
+ LogPrint(BCLog::NET, "Added connection peer=%d\n", id);
}
-
- if (fLogIPs)
- LogPrint("net", "Added connection to %s peer=%d\n", addrName, id);
- else
- LogPrint("net", "Added connection peer=%d\n", id);
-
- // Be shy and don't send version until we hear
- if (hSocket != INVALID_SOCKET && !fInbound)
- PushVersion();
-
- GetNodeSignals().InitializeNode(GetId(), this);
}
CNode::~CNode()
@@ -2494,8 +2699,6 @@ CNode::~CNode()
if (pfilter)
delete pfilter;
-
- GetNodeSignals().FinalizeNode(GetId());
}
void CNode::AskFor(const CInv& inv)
@@ -2514,7 +2717,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;
@@ -2532,180 +2735,73 @@ void CNode::AskFor(const CInv& inv)
mapAskFor.insert(std::make_pair(nRequestTime, inv));
}
-void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend)
+bool CConnman::NodeFullyConnected(const CNode* pnode)
{
- ENTER_CRITICAL_SECTION(cs_vSend);
- assert(ssSend.size() == 0);
- ssSend << CMessageHeader(Params().MessageStart(), pszCommand, 0);
- LogPrint("net", "sending: %s ", SanitizeString(pszCommand));
+ return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect;
}
-void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend)
+void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
{
- ssSend.clear();
-
- LEAVE_CRITICAL_SECTION(cs_vSend);
+ size_t nMessageSize = msg.data.size();
+ size_t nTotalSize = nMessageSize + CMessageHeader::HEADER_SIZE;
+ LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", SanitizeString(msg.command.c_str()), nMessageSize, pnode->GetId());
- LogPrint("net", "(aborted)\n");
-}
+ std::vector<unsigned char> serializedHeader;
+ serializedHeader.reserve(CMessageHeader::HEADER_SIZE);
+ uint256 hash = Hash(msg.data.data(), msg.data.data() + nMessageSize);
+ CMessageHeader hdr(Params().MessageStart(), msg.command.c_str(), nMessageSize);
+ memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);
-void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend)
-{
- // The -*messagestest options are intentionally not documented in the help message,
- // since they are only used during development to debug the networking code and are
- // not intended for end-users.
- if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0)
- {
- LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n");
- AbortMessage();
- return;
- }
- if (mapArgs.count("-fuzzmessagestest"))
- Fuzz(GetArg("-fuzzmessagestest", 10));
+ CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, serializedHeader, 0, hdr};
- if (ssSend.size() == 0)
+ size_t nBytesSent = 0;
{
- LEAVE_CRITICAL_SECTION(cs_vSend);
- return;
- }
- // Set the size
- unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
- WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
-
- //log total amount of bytes per command
- mapSendBytesPerMsgCmd[std::string(pszCommand)] += nSize + CMessageHeader::HEADER_SIZE;
-
- // Set the checksum
- uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());
- unsigned int nChecksum = 0;
- memcpy(&nChecksum, &hash, sizeof(nChecksum));
- assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
- memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum));
-
- LogPrint("net", "(%d bytes) peer=%d\n", nSize, id);
-
- std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData());
- ssSend.GetAndClear(*it);
- nSendSize += (*it).size();
-
- // If write queue empty, attempt "optimistic write"
- if (it == vSendMsg.begin())
- SocketSendData(this);
+ LOCK(pnode->cs_vSend);
+ bool optimisticSend(pnode->vSendMsg.empty());
- LEAVE_CRITICAL_SECTION(cs_vSend);
-}
+ //log total amount of bytes per command
+ pnode->mapSendBytesPerMsgCmd[msg.command] += nTotalSize;
+ pnode->nSendSize += nTotalSize;
-//
-// CBanDB
-//
+ if (pnode->nSendSize > nSendBufferMaxSize)
+ pnode->fPauseSend = true;
+ pnode->vSendMsg.push_back(std::move(serializedHeader));
+ if (nMessageSize)
+ pnode->vSendMsg.push_back(std::move(msg.data));
-CBanDB::CBanDB()
-{
- pathBanlist = GetDataDir() / "banlist.dat";
-}
-
-bool CBanDB::Write(const banmap_t& banSet)
-{
- // Generate random temporary filename
- unsigned short randv = 0;
- GetRandBytes((unsigned char*)&randv, sizeof(randv));
- std::string tmpfn = strprintf("banlist.dat.%04x", randv);
-
- // serialize banlist, checksum data up to that point, then append csum
- CDataStream ssBanlist(SER_DISK, CLIENT_VERSION);
- ssBanlist << FLATDATA(Params().MessageStart());
- ssBanlist << banSet;
- uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end());
- ssBanlist << hash;
-
- // open temp output file, and associate with CAutoFile
- boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
- FILE *file = fopen(pathTmp.string().c_str(), "wb");
- CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
- if (fileout.IsNull())
- return error("%s: Failed to open file %s", __func__, pathTmp.string());
-
- // Write and commit header, data
- try {
- fileout << ssBanlist;
+ // If write queue empty, attempt "optimistic write"
+ if (optimisticSend == true)
+ nBytesSent = SocketSendData(pnode);
}
- catch (const std::exception& e) {
- return error("%s: Serialize or I/O error - %s", __func__, e.what());
- }
- FileCommit(fileout.Get());
- fileout.fclose();
-
- // replace existing banlist.dat, if any, with new banlist.dat.XXXX
- if (!RenameOver(pathTmp, pathBanlist))
- return error("%s: Rename-into-place failed", __func__);
-
- return true;
+ if (nBytesSent)
+ RecordBytesSent(nBytesSent);
}
-bool CBanDB::Read(banmap_t& banSet)
+bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)
{
- // 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 {
- // de-serialize file header (network specific magic number) and ..
- ssBanlist >> FLATDATA(pchMsgTmp);
-
- // ... verify the network matches ours
- if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
- return error("%s: Invalid network magic number", __func__);
-
- // de-serialize address data into one CAddrMan object
- ssBanlist >> banSet;
- }
- catch (const std::exception& e) {
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ CNode* found = nullptr;
+ LOCK(cs_vNodes);
+ for (auto&& pnode : vNodes) {
+ if(pnode->GetId() == id) {
+ found = pnode;
+ break;
+ }
}
-
- return true;
+ 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);
}
-/* static */ uint64_t CNode::CalculateKeyedNetGroup(const CAddress& ad)
+CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const
{
- static const uint64_t k0 = GetRand(std::numeric_limits<uint64_t>::max());
- static const uint64_t k1 = GetRand(std::numeric_limits<uint64_t>::max());
+ return CSipHasher(nSeed0, nSeed1).Write(id);
+}
+uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const
+{
std::vector<unsigned char> vchNetGroup(ad.GetGroup());
- return CSipHasher(k0, k1).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize();
+ return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize();
}
diff --git a/src/net.h b/src/net.h
index 41315fc9b9..bea04bc580 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1,35 +1,41 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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_NET_H
#define BITCOIN_NET_H
+#include "addrdb.h"
+#include "addrman.h"
#include "amount.h"
#include "bloom.h"
#include "compat.h"
+#include "hash.h"
#include "limitedmap.h"
-#include "netbase.h"
+#include "netaddress.h"
+#include "policy/feerate.h"
#include "protocol.h"
#include "random.h"
#include "streams.h"
#include "sync.h"
#include "uint256.h"
+#include "threadinterrupt.h"
#include <atomic>
#include <deque>
#include <stdint.h>
+#include <thread>
+#include <memory>
+#include <condition_variable>
#ifndef WIN32
#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;
@@ -41,6 +47,8 @@ namespace boost {
static const int PING_INTERVAL = 2 * 60;
/** Time after which to disconnect, after waiting for a ping response (or inactivity). */
static const int TIMEOUT_INTERVAL = 20 * 60;
+/** Run the feeler connection loop once every 2 minutes or 120 seconds. **/
+static const int FEELER_INTERVAL = 120;
/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
/** The maximum number of new addresses to accumulate before announcing. */
@@ -49,6 +57,10 @@ static const unsigned int MAX_ADDR_TO_SEND = 1000;
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000;
/** Maximum length of strSubVer in `version` message */
static const unsigned int MAX_SUBVERSION_LENGTH = 256;
+/** Maximum number of automatic outgoing nodes */
+static const int MAX_OUTBOUND_CONNECTIONS = 8;
+/** Maximum number of addnode outgoing nodes */
+static const int MAX_ADDNODE_CONNECTIONS = 8;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** -upnp default */
@@ -65,6 +77,8 @@ static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ;
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
/** The default for -maxuploadtarget. 0 = Unlimited */
static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0;
+/** The default timeframe for -maxuploadtarget. 1 day. */
+static const uint64_t MAX_UPLOAD_TIMEFRAME = 60 * 60 * 24;
/** Default for blocks only*/
static const bool DEFAULT_BLOCKSONLY = false;
@@ -77,25 +91,321 @@ 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
-unsigned int ReceiveFloodSize();
-unsigned int SendBufferSize();
+typedef int64_t NodeId;
-typedef int NodeId;
+struct AddedNodeInfo
+{
+ std::string strAddedNode;
+ CService resolvedAddress;
+ bool fConnected;
+ bool fInbound;
+};
+
+class CTransaction;
+class CNodeStats;
+class CClientUIInterface;
+
+struct CSerializedNetMsg
+{
+ CSerializedNetMsg() = default;
+ CSerializedNetMsg(CSerializedNetMsg&&) = default;
+ CSerializedNetMsg& operator=(CSerializedNetMsg&&) = default;
+ // No copying, only moves.
+ CSerializedNetMsg(const CSerializedNetMsg& msg) = delete;
+ CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete;
+
+ std::vector<unsigned char> data;
+ std::string command;
+};
+
+
+class CConnman
+{
+public:
+
+ enum NumConnections {
+ CONNECTIONS_NONE = 0,
+ CONNECTIONS_IN = (1U << 0),
+ CONNECTIONS_OUT = (1U << 1),
+ CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),
+ };
+
+ struct Options
+ {
+ ServiceFlags nLocalServices = NODE_NONE;
+ ServiceFlags nRelevantServices = NODE_NONE;
+ int nMaxConnections = 0;
+ int nMaxOutbound = 0;
+ int nMaxAddnode = 0;
+ int nMaxFeeler = 0;
+ int nBestHeight = 0;
+ CClientUIInterface* uiInterface = nullptr;
+ unsigned int nSendBufferMaxSize = 0;
+ unsigned int nReceiveFloodSize = 0;
+ uint64_t nMaxOutboundTimeframe = 0;
+ uint64_t nMaxOutboundLimit = 0;
+ };
+ CConnman(uint64_t seed0, uint64_t seed1);
+ ~CConnman();
+ bool Start(CScheduler& scheduler, std::string& strNodeError, 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 CheckIncomingNonce(uint64_t nonce);
+
+ bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
+
+ void PushMessage(CNode* pnode, CSerializedNetMsg&& msg);
+
+ template<typename Callable>
+ void ForEachNode(Callable&& func)
+ {
+ LOCK(cs_vNodes);
+ for (auto&& node : vNodes) {
+ if (NodeFullyConnected(node))
+ func(node);
+ }
+ };
+
+ template<typename Callable>
+ void ForEachNode(Callable&& func) const
+ {
+ LOCK(cs_vNodes);
+ 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) {
+ if (NodeFullyConnected(node))
+ pre(node);
+ }
+ post();
+ };
+
+ template<typename Callable, typename CallableAfter>
+ void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const
+ {
+ LOCK(cs_vNodes);
+ for (auto&& node : vNodes) {
+ if (NodeFullyConnected(node))
+ pre(node);
+ }
+ post();
+ };
+
+ // Addrman functions
+ size_t GetAddressCount() const;
+ void SetServices(const CService &addr, ServiceFlags nServices);
+ void MarkAddressGood(const CAddress& addr);
+ void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
+ std::vector<CAddress> GetAddresses();
+
+ // Denial-of-service detection/prevention
+ // The idea is to detect peers that are behaving
+ // badly and disconnect/ban them, but do it in a
+ // one-coding-mistake-won't-shatter-the-entire-network
+ // way.
+ // IMPORTANT: There should be nothing I can give a
+ // node that it will forward on that will make that
+ // node's peers drop it. If there is, an attacker
+ // can isolate a node and/or try to split the network.
+ // Dropping a node for sending stuff that is invalid
+ // now but might be valid in a later version is also
+ // dangerous, because it can cause a network split
+ // between nodes running old code and nodes running
+ // new code.
+ void Ban(const CNetAddr& netAddr, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ void Ban(const CSubNet& subNet, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ void ClearBanned(); // needed for unit testing
+ bool IsBanned(CNetAddr ip);
+ bool IsBanned(CSubNet subnet);
+ bool Unban(const CNetAddr &ip);
+ bool Unban(const CSubNet &ip);
+ 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 DisconnectNode(const std::string& node);
+ bool DisconnectNode(NodeId id);
+
+ unsigned int GetSendBufferSize() const;
+
+ void AddWhitelistedRange(const CSubNet &subnet);
+
+ ServiceFlags GetLocalServices() const;
+
+ //!set the max outbound target in bytes
+ void SetMaxOutboundTarget(uint64_t limit);
+ uint64_t GetMaxOutboundTarget();
+
+ //!set the timeframe for the max outbound target
+ void SetMaxOutboundTimeframe(uint64_t timeframe);
+ uint64_t GetMaxOutboundTimeframe();
+
+ //!check if the outbound target is reached
+ // if param historicalBlockServingLimit is set true, the function will
+ // response true if the limit for serving historical blocks has been reached
+ bool OutboundTargetReached(bool historicalBlockServingLimit);
+
+ //!response the bytes left in the current max outbound cycle
+ // in case of no limit, it will always response 0
+ uint64_t GetOutboundTargetBytesLeft();
+
+ //!response the time in second left in the current max outbound cycle
+ // in case of no limit, it will always response 0
+ uint64_t GetMaxOutboundTimeLeftInCycle();
+
+ uint64_t GetTotalBytesRecv();
+ uint64_t GetTotalBytesSent();
+
+ void SetBestHeight(int height);
+ int GetBestHeight() const;
+
+ /** Get a unique deterministic randomizer. */
+ CSipHasher GetDeterministicRandomizer(uint64_t id) const;
+
+ unsigned int GetReceiveFloodSize() const;
+
+ void WakeMessageHandler();
+private:
+ struct ListenSocket {
+ SOCKET socket;
+ bool whitelisted;
+
+ ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {}
+ };
+
+ void ThreadOpenAddedConnections();
+ void ProcessOneShot();
+ void ThreadOpenConnections();
+ void ThreadMessageHandler();
+ void AcceptConnection(const ListenSocket& hListenSocket);
+ void ThreadSocketHandler();
+ void ThreadDNSAddressSeed();
-void AddOneShot(const std::string& strDest);
-void AddressCurrentlyConnected(const CService& addr);
-CNode* FindNode(const CNetAddr& ip);
-CNode* FindNode(const CSubNet& subNet);
-CNode* FindNode(const std::string& addrName);
-CNode* FindNode(const CService& ip);
-CNode* FindNode(const NodeId id); //TODO: Remove this
-bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
+ uint64_t CalculateKeyedNetGroup(const CAddress& ad) const;
+
+ CNode* FindNode(const CNetAddr& ip);
+ CNode* FindNode(const CSubNet& subNet);
+ CNode* FindNode(const std::string& addrName);
+ CNode* FindNode(const CService& addr);
+
+ bool AttemptToEvictConnection();
+ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure);
+ bool IsWhitelistedRange(const CNetAddr &addr);
+
+ void DeleteNode(CNode* pnode);
+
+ NodeId GetNewNodeId();
+
+ size_t SocketSendData(CNode *pnode) const;
+ //!check is the banlist has unwritten changes
+ bool BannedSetIsDirty();
+ //!set the "dirty" flag for the banlist
+ void SetBannedSetDirty(bool dirty=true);
+ //!clean unused entries (if bantime has expired)
+ void SweepBanned();
+ void DumpAddresses();
+ void DumpData();
+ void DumpBanlist();
+
+ // Network stats
+ 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;
+ uint64_t nTotalBytesRecv;
+ uint64_t nTotalBytesSent;
+
+ // outbound limit & stats
+ uint64_t nMaxOutboundTotalBytesSentInCycle;
+ uint64_t nMaxOutboundCycleStartTime;
+ uint64_t nMaxOutboundLimit;
+ uint64_t nMaxOutboundTimeframe;
+
+ // 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;
+
+ std::vector<ListenSocket> vhListenSocket;
+ std::atomic<bool> fNetworkActive;
+ banmap_t setBanned;
+ CCriticalSection cs_setBanned;
+ bool setBannedIsDirty;
+ bool fAddressesInitialized;
+ CAddrMan addrman;
+ std::deque<std::string> vOneShots;
+ CCriticalSection cs_vOneShots;
+ std::vector<std::string> vAddedNodes;
+ CCriticalSection cs_vAddedNodes;
+ std::vector<CNode*> vNodes;
+ std::list<CNode*> vNodesDisconnected;
+ mutable CCriticalSection cs_vNodes;
+ std::atomic<NodeId> nLastNodeId;
+
+ /** Services this instance offers */
+ ServiceFlags nLocalServices;
+
+ /** Services this instance cares about */
+ ServiceFlags nRelevantServices;
+
+ CSemaphore *semOutbound;
+ CSemaphore *semAddnode;
+ int nMaxConnections;
+ int nMaxOutbound;
+ int nMaxAddnode;
+ int nMaxFeeler;
+ std::atomic<int> nBestHeight;
+ CClientUIInterface* clientInterface;
+
+ /** SipHasher seeds for deterministic randomness */
+ const uint64_t nSeed0, nSeed1;
+
+ /** flag for waking the message processor. */
+ bool fMsgProcWake;
+
+ std::condition_variable condMsgProc;
+ std::mutex mutexMsgProc;
+ std::atomic<bool> flagInterruptMsgProc;
+
+ CThreadInterrupt interruptNet;
+
+ std::thread threadDNSAddressSeed;
+ std::thread threadSocketHandler;
+ std::thread threadOpenAddedConnections;
+ std::thread threadOpenConnections;
+ std::thread threadMessageHandler;
+};
+extern std::unique_ptr<CConnman> g_connman;
+void Discover(boost::thread_group& threadGroup);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
-void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler);
-bool StopNode();
-void SocketSendData(CNode *pnode);
struct CombinerAll
{
@@ -115,11 +425,10 @@ struct CombinerAll
// Signals for message handling
struct CNodeSignals
{
- boost::signals2::signal<int ()> GetHeight;
- boost::signals2::signal<bool (CNode*), CombinerAll> ProcessMessages;
- boost::signals2::signal<bool (CNode*), CombinerAll> SendMessages;
- boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode;
- boost::signals2::signal<void (NodeId)> FinalizeNode;
+ 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;
};
@@ -150,30 +459,15 @@ bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
bool IsReachable(enum Network net);
bool IsReachable(const CNetAddr &addr);
-CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
+CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices);
extern bool fDiscover;
extern bool fListen;
-extern ServiceFlags nLocalServices;
-extern ServiceFlags nRelevantServices;
extern bool fRelayTxes;
-extern uint64_t nLocalHostNonce;
-extern CAddrMan addrman;
-/** Maximum number of connections to simultaneously allow (aka connection slots) */
-extern int nMaxConnections;
-
-extern std::vector<CNode*> vNodes;
-extern CCriticalSection cs_vNodes;
extern limitedmap<uint256, int64_t> mapAlreadyAskedFor;
-extern std::vector<std::string> vAddedNodes;
-extern CCriticalSection cs_vAddedNodes;
-
-extern NodeId nLastNodeId;
-extern CCriticalSection cs_nLastNodeId;
-
/** Subversion as sent to the P2P network in `version` messages */
extern std::string strSubVersion;
@@ -200,6 +494,7 @@ public:
int nVersion;
std::string cleanSubVer;
bool fInbound;
+ bool fAddnode;
int nStartingHeight;
uint64_t nSendBytes;
mapMsgCmdSize mapSendBytesPerMsgCmd;
@@ -208,14 +503,18 @@ public:
bool fWhitelisted;
double dPingTime;
double dPingWait;
- double dPingMin;
+ double dMinPing;
std::string addrLocal;
+ CAddress addr;
};
class CNetMessage {
+private:
+ mutable CHash256 hasher;
+ mutable uint256 data_hash;
public:
bool in_data; // parsing header (false) or data (true)
@@ -243,6 +542,8 @@ public:
return (hdr.nMessageSize == nDataPos);
}
+ const uint256& GetMessageHash() const;
+
void SetVersion(int nVersionIn)
{
hdrbuf.SetVersion(nVersionIn);
@@ -254,108 +555,53 @@ public:
};
-typedef enum BanReason
-{
- BanReasonUnknown = 0,
- BanReasonNodeMisbehaving = 1,
- BanReasonManuallyAdded = 2
-} BanReason;
-
-class CBanEntry
-{
-public:
- static const int CURRENT_VERSION=1;
- int nVersion;
- int64_t nCreateTime;
- int64_t nBanUntil;
- uint8_t banReason;
-
- CBanEntry()
- {
- SetNull();
- }
-
- CBanEntry(int64_t nCreateTimeIn)
- {
- SetNull();
- nCreateTime = nCreateTimeIn;
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(this->nVersion);
- nVersion = this->nVersion;
- READWRITE(nCreateTime);
- READWRITE(nBanUntil);
- READWRITE(banReason);
- }
-
- void SetNull()
- {
- nVersion = CBanEntry::CURRENT_VERSION;
- nCreateTime = 0;
- nBanUntil = 0;
- banReason = BanReasonUnknown;
- }
-
- std::string banReasonToString()
- {
- switch (banReason) {
- case BanReasonNodeMisbehaving:
- return "node misbehaving";
- case BanReasonManuallyAdded:
- return "manually added";
- default:
- return "unknown";
- }
- }
-};
-
-typedef std::map<CSubNet, CBanEntry> banmap_t;
-
/** Information about a peer */
class CNode
{
+ friend class CConnman;
public:
// socket
- ServiceFlags nServices;
+ std::atomic<ServiceFlags> nServices;
ServiceFlags nServicesExpected;
SOCKET hSocket;
- CDataStream ssSend;
size_t nSendSize; // total size of all vSendMsg entries
size_t nSendOffset; // offset inside the first vSendMsg already sent
uint64_t nSendBytes;
- std::deque<CSerializeData> vSendMsg;
+ 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;
- std::deque<CNetMessage> vRecvMsg;
- CCriticalSection cs_vRecvMsg;
uint64_t nRecvBytes;
- int nRecvVersion;
+ 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;
const CAddress addr;
- std::string addrName;
- CService addrLocal;
- int nVersion;
+ 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;
- bool fInbound;
- bool fNetworkNode;
- bool fSuccessfullyConnected;
- bool fDisconnect;
+ const bool fInbound;
+ 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
// b) the peer may tell us in its version message that we should not relay tx invs
@@ -365,32 +611,19 @@ public:
CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter;
CBloomFilter* pfilter;
- int nRefCount;
- NodeId id;
+ std::atomic<int> nRefCount;
const uint64_t nKeyedNetGroup;
+ std::atomic_bool fPauseRecv;
+ std::atomic_bool fPauseSend;
protected:
- // Denial-of-service detection/prevention
- // Key is IP address, value is banned-until-time
- static banmap_t setBanned;
- static CCriticalSection cs_setBanned;
- static bool setBannedIsDirty;
-
- // Whitelisted ranges. Any node connecting from these is automatically
- // whitelisted (as well as those connecting to whitelisted binds).
- static std::vector<CSubNet> vWhitelistedRange;
- static CCriticalSection cs_vWhitelistedRange;
-
mapMsgCmdSize mapSendBytesPerMsgCmd;
mapMsgCmdSize mapRecvBytesPerMsgCmd;
- // Basic fuzz-testing
- void Fuzz(int nChance); // modifies ssSend
-
public:
uint256 hashContinue;
- int nStartingHeight;
+ std::atomic<int> nStartingHeight;
// flood relay
std::vector<CAddress> vAddrToSend;
@@ -428,46 +661,54 @@ 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(SOCKET hSocketIn, const CAddress &addrIn, 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 std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
private:
- // Network usage totals
- static CCriticalSection cs_totalBytesRecv;
- static CCriticalSection cs_totalBytesSent;
- static uint64_t nTotalBytesRecv;
- static uint64_t nTotalBytesSent;
-
- // outbound limit & stats
- static uint64_t nMaxOutboundTotalBytesSentInCycle;
- static uint64_t nMaxOutboundCycleStartTime;
- static uint64_t nMaxOutboundLimit;
- static uint64_t nMaxOutboundTimeframe;
-
CNode(const CNode&);
void operator=(const CNode&);
+ const NodeId id;
- static uint64_t CalculateKeyedNetGroup(const CAddress& ad);
+ 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;
+
+ CService addrLocal;
+ mutable CCriticalSection cs_addrLocal;
public:
NodeId GetId() const {
- return id;
+ return id;
+ }
+
+ uint64_t GetLocalNonce() const {
+ return nLocalHostNonce;
+ }
+
+ int GetMyStartingHeight() const {
+ return nMyStartingHeight;
}
int GetRefCount()
@@ -476,25 +717,22 @@ public:
return nRefCount;
}
- // requires LOCK(cs_vRecvMsg)
- unsigned int GetTotalRecvSize()
- {
- unsigned int total = 0;
- BOOST_FOREACH(const CNetMessage &msg, vRecvMsg)
- total += msg.vRecv.size() + 24;
- return total;
- }
-
- // requires LOCK(cs_vRecvMsg)
- bool ReceiveMsgBytes(const char *pch, unsigned int nBytes);
+ bool ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete);
- // requires LOCK(cs_vRecvMsg)
void SetRecvVersion(int nVersionIn)
{
nRecvVersion = nVersionIn;
- BOOST_FOREACH(CNetMessage &msg, vRecvMsg)
- msg.SetVersion(nVersionIn);
}
+ int GetRecvVersion()
+ {
+ return nRecvVersion;
+ }
+ void SetSendVersion(int nVersionIn);
+ int GetSendVersion() const;
+
+ CService GetAddrLocal() const;
+ //! May not be called more than once
+ void SetAddrLocal(const CService& addrLocalIn);
CNode* AddRef()
{
@@ -509,21 +747,21 @@ public:
- void AddAddressKnown(const CAddress& addr)
+ void AddAddressKnown(const CAddress& _addr)
{
- addrKnown.insert(addr.GetKey());
+ addrKnown.insert(_addr.GetKey());
}
- void PushAddress(const CAddress& addr)
+ void PushAddress(const CAddress& _addr, FastRandomContext &insecure_rand)
{
// Known checking here is only to save space from duplicates.
// SendMessages will filter it again for knowns that were added
// after addresses were pushed.
- if (addr.IsValid() && !addrKnown.contains(addr.GetKey())) {
+ if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) {
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
- vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr;
+ vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] = _addr;
} else {
- vAddrToSend.push_back(addr);
+ vAddrToSend.push_back(_addr);
}
}
}
@@ -557,299 +795,25 @@ public:
void AskFor(const CInv& inv);
- // TODO: Document the postcondition of this function. Is cs_vSend locked?
- void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend);
-
- // TODO: Document the precondition of this function. Is cs_vSend locked?
- void AbortMessage() UNLOCK_FUNCTION(cs_vSend);
-
- // TODO: Document the precondition of this function. Is cs_vSend locked?
- void EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend);
-
- void PushVersion();
-
-
- void PushMessage(const char* pszCommand)
- {
- try
- {
- BeginMessage(pszCommand);
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1>
- void PushMessage(const char* pszCommand, const T1& a1)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- /** Send a message containing a1, serialized with flag flag. */
- template<typename T1>
- void PushMessageWithFlag(int flag, const char* pszCommand, const T1& a1)
- {
- try
- {
- BeginMessage(pszCommand);
- WithOrVersion(&ssSend, flag) << a1;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4, typename T5>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4 << a5;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4 << a5 << a6;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
- template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
- void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9)
- {
- try
- {
- BeginMessage(pszCommand);
- ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
- EndMessage(pszCommand);
- }
- catch (...)
- {
- AbortMessage();
- throw;
- }
- }
-
void CloseSocketDisconnect();
- // Denial-of-service detection/prevention
- // The idea is to detect peers that are behaving
- // badly and disconnect/ban them, but do it in a
- // one-coding-mistake-won't-shatter-the-entire-network
- // way.
- // IMPORTANT: There should be nothing I can give a
- // node that it will forward on that will make that
- // node's peers drop it. If there is, an attacker
- // can isolate a node and/or try to split the network.
- // Dropping a node for sending stuff that is invalid
- // now but might be valid in a later version is also
- // dangerous, because it can cause a network split
- // between nodes running old code and nodes running
- // new code.
- static void ClearBanned(); // needed for unit testing
- static bool IsBanned(CNetAddr ip);
- static bool IsBanned(CSubNet subnet);
- static void Ban(const CNetAddr &ip, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
- static void Ban(const CSubNet &subNet, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
- static bool Unban(const CNetAddr &ip);
- static bool Unban(const CSubNet &ip);
- static void GetBanned(banmap_t &banmap);
- static void SetBanned(const banmap_t &banmap);
-
- //!check is the banlist has unwritten changes
- static bool BannedSetIsDirty();
- //!set the "dirty" flag for the banlist
- static void SetBannedSetDirty(bool dirty=true);
- //!clean unused entries (if bantime has expired)
- static void SweepBanned();
-
void copyStats(CNodeStats &stats);
- static bool IsWhitelistedRange(const CNetAddr &ip);
- static void AddWhitelistedRange(const CSubNet &subnet);
-
- // Network stats
- static void RecordBytesRecv(uint64_t bytes);
- static void RecordBytesSent(uint64_t bytes);
-
- static uint64_t GetTotalBytesRecv();
- static uint64_t GetTotalBytesSent();
-
- //!set the max outbound target in bytes
- static void SetMaxOutboundTarget(uint64_t limit);
- static uint64_t GetMaxOutboundTarget();
-
- //!set the timeframe for the max outbound target
- static void SetMaxOutboundTimeframe(uint64_t timeframe);
- static uint64_t GetMaxOutboundTimeframe();
-
- //!check if the outbound target is reached
- // if param historicalBlockServingLimit is set true, the function will
- // response true if the limit for serving historical blocks has been reached
- static bool OutboundTargetReached(bool historicalBlockServingLimit);
-
- //!response the bytes left in the current max outbound cycle
- // in case of no limit, it will always response 0
- static uint64_t GetOutboundTargetBytesLeft();
+ ServiceFlags GetLocalServices() const
+ {
+ return nLocalServices;
+ }
- //!response the time in second left in the current max outbound cycle
- // in case of no limit, it will always response 0
- static uint64_t GetMaxOutboundTimeLeftInCycle();
+ std::string GetAddrName() const;
+ //! Sets the addrName only if it was not previously set
+ void MaybeSetAddrName(const std::string& addrNameIn);
};
-class CTransaction;
-void RelayTransaction(const CTransaction& tx);
-/** Access to the (IP) address database (peers.dat) */
-class CAddrDB
-{
-private:
- boost::filesystem::path pathAddr;
-public:
- CAddrDB();
- bool Write(const CAddrMan& addr);
- bool Read(CAddrMan& addr);
- bool Read(CAddrMan& addr, CDataStream& ssPeers);
-};
-
-/** Access to the banlist database (banlist.dat) */
-class CBanDB
-{
-private:
- boost::filesystem::path pathBanlist;
-public:
- CBanDB();
- bool Write(const banmap_t& banSet);
- bool Read(banmap_t& banSet);
-};
/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);
-struct AddedNodeInfo
-{
- std::string strAddedNode;
- CService resolvedAddress;
- bool fConnected;
- bool fInbound;
-};
-
-std::vector<AddedNodeInfo> GetAddedNodeInfo();
-
#endif // BITCOIN_NET_H
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
new file mode 100644
index 0000000000..eeef26fa97
--- /dev/null
+++ b/src/net_processing.cpp
@@ -0,0 +1,3298 @@
+// 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.
+
+#include "net_processing.h"
+
+#include "addrman.h"
+#include "arith_uint256.h"
+#include "blockencodings.h"
+#include "chainparams.h"
+#include "consensus/validation.h"
+#include "hash.h"
+#include "init.h"
+#include "validation.h"
+#include "merkleblock.h"
+#include "net.h"
+#include "netmessagemaker.h"
+#include "netbase.h"
+#include "policy/fees.h"
+#include "policy/policy.h"
+#include "primitives/block.h"
+#include "primitives/transaction.h"
+#include "random.h"
+#include "tinyformat.h"
+#include "txmempool.h"
+#include "ui_interface.h"
+#include "util.h"
+#include "utilmoneystr.h"
+#include "utilstrencodings.h"
+#include "validationinterface.h"
+
+#include <boost/thread.hpp>
+
+#if defined(NDEBUG)
+# error "Bitcoin cannot be compiled without assertions."
+#endif
+
+std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block
+
+struct IteratorComparator
+{
+ template<typename I>
+ bool operator()(const I& a, const I& b)
+ {
+ return &(*a) < &(*b);
+ }
+};
+
+struct COrphanTx {
+ // When modifying, adapt the copy of this definition in tests/DoS_tests.
+ CTransactionRef tx;
+ NodeId fromPeer;
+ int64_t nTimeExpire;
+};
+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
+namespace {
+ /** Number of nodes with fSyncStarted. */
+ int nSyncStarted = 0;
+
+ /**
+ * Sources of received blocks, saved to be able to send them reject
+ * messages or ban them when processing happens afterwards. Protected by
+ * cs_main.
+ * Set mapBlockSource[hash].second to false if the node should not be
+ * punished if the block is invalid.
+ */
+ std::map<uint256, std::pair<NodeId, bool>> mapBlockSource;
+
+ /**
+ * Filter for transactions that were recently rejected by
+ * AcceptToMemoryPool. These are not rerequested until the chain tip
+ * changes, at which point the entire filter is reset. Protected by
+ * cs_main.
+ *
+ * Without this filter we'd be re-requesting txs from each of our peers,
+ * increasing bandwidth consumption considerably. For instance, with 100
+ * peers, half of which relay a tx we don't accept, that might be a 50x
+ * bandwidth increase. A flooding attacker attempting to roll-over the
+ * filter using minimum-sized, 60byte, transactions might manage to send
+ * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a
+ * two minute window to send invs to us.
+ *
+ * Decreasing the false positive rate is fairly cheap, so we pick one in a
+ * million to make it highly unlikely for users to have issues with this
+ * filter.
+ *
+ * Memory used: 1.3 MB
+ */
+ std::unique_ptr<CRollingBloomFilter> recentRejects;
+ uint256 hashRecentRejectsChainTip;
+
+ /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
+ struct QueuedBlock {
+ uint256 hash;
+ const CBlockIndex* pindex; //!< Optional.
+ bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request.
+ std::unique_ptr<PartiallyDownloadedBlock> partialBlock; //!< Optional, used for CMPCTBLOCK downloads
+ };
+ std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> > mapBlocksInFlight;
+
+ /** Stack of nodes which we have set to announce using compact blocks */
+ std::list<NodeId> lNodesAnnouncingHeaderAndIDs;
+
+ /** Number of preferable block download peers. */
+ int nPreferredDownload = 0;
+
+ /** Number of peers from which we're downloading blocks. */
+ int nPeersWithValidatedDownloads = 0;
+
+ /** Relay map, protected by cs_main. */
+ typedef std::map<uint256, CTransactionRef> MapRelay;
+ 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 {
+
+struct CBlockReject {
+ unsigned char chRejectCode;
+ std::string strRejectReason;
+ uint256 hashBlock;
+};
+
+/**
+ * Maintain validation-specific state about nodes, protected by cs_main, instead
+ * by CNode's own locks. This simplifies asynchronous operation, where
+ * processing of incoming data is done after the ProcessMessage call returns,
+ * and we're no longer holding the node's locks.
+ */
+struct CNodeState {
+ //! The peer's address
+ const CService address;
+ //! Whether we have a fully established connection.
+ bool fCurrentlyConnected;
+ //! Accumulated misbehaviour score for this peer.
+ int nMisbehavior;
+ //! Whether this peer should be disconnected and banned (unless whitelisted).
+ bool fShouldBan;
+ //! String name of this peer (debugging/logging purposes).
+ const std::string name;
+ //! List of asynchronously-determined block rejections to notify this peer about.
+ std::vector<CBlockReject> rejects;
+ //! The best known block we know this peer has announced.
+ const CBlockIndex *pindexBestKnownBlock;
+ //! The hash of the last unknown block this peer has announced.
+ uint256 hashLastUnknownBlock;
+ //! The last full block we both have.
+ const CBlockIndex *pindexLastCommonBlock;
+ //! The best header we have sent our peer.
+ const CBlockIndex *pindexBestHeaderSent;
+ //! Length of current-streak of unconnecting headers announcements
+ int nUnconnectingHeaders;
+ //! Whether we've started headers synchronization with this peer.
+ bool fSyncStarted;
+ //! Since when we're stalling block download progress (in microseconds), or 0.
+ int64_t nStallingSince;
+ std::list<QueuedBlock> vBlocksInFlight;
+ //! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
+ int64_t nDownloadingSince;
+ int nBlocksInFlight;
+ int nBlocksInFlightValidHeaders;
+ //! Whether we consider this a preferred download peer.
+ bool fPreferredDownload;
+ //! Whether this peer wants invs or headers (when possible) for block announcements.
+ bool fPreferHeaders;
+ //! Whether this peer wants invs or cmpctblocks (when possible) for block announcements.
+ bool fPreferHeaderAndIDs;
+ /**
+ * Whether this peer will send us cmpctblocks if we request them.
+ * This is not used to gate request logic, as we really only care about fSupportsDesiredCmpctVersion,
+ * but is used as a flag to "lock in" the version of compact blocks (fWantsCmpctWitness) we send.
+ */
+ bool fProvidesHeaderAndIDs;
+ //! Whether this peer can give us witnesses
+ bool fHaveWitness;
+ //! Whether this peer wants witnesses in cmpctblocks/blocktxns
+ bool fWantsCmpctWitness;
+ /**
+ * If we've announced NODE_WITNESS to this peer: whether the peer sends witnesses in cmpctblocks/blocktxns,
+ * otherwise: whether this peer sends non-witnesses in cmpctblocks/blocktxns.
+ */
+ bool fSupportsDesiredCmpctVersion;
+
+ CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) {
+ fCurrentlyConnected = false;
+ nMisbehavior = 0;
+ fShouldBan = false;
+ pindexBestKnownBlock = NULL;
+ hashLastUnknownBlock.SetNull();
+ pindexLastCommonBlock = NULL;
+ pindexBestHeaderSent = NULL;
+ nUnconnectingHeaders = 0;
+ fSyncStarted = false;
+ nStallingSince = 0;
+ nDownloadingSince = 0;
+ nBlocksInFlight = 0;
+ nBlocksInFlightValidHeaders = 0;
+ fPreferredDownload = false;
+ fPreferHeaders = false;
+ fPreferHeaderAndIDs = false;
+ fProvidesHeaderAndIDs = false;
+ fHaveWitness = false;
+ fWantsCmpctWitness = false;
+ fSupportsDesiredCmpctVersion = false;
+ }
+};
+
+/** Map maintaining per-node state. Requires cs_main. */
+std::map<NodeId, CNodeState> mapNodeState;
+
+// Requires cs_main.
+CNodeState *State(NodeId pnode) {
+ std::map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);
+ if (it == mapNodeState.end())
+ return NULL;
+ return &it->second;
+}
+
+void UpdatePreferredDownload(CNode* node, CNodeState* state)
+{
+ nPreferredDownload -= state->fPreferredDownload;
+
+ // Whether this node should be marked as a preferred download node.
+ state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient;
+
+ nPreferredDownload += state->fPreferredDownload;
+}
+
+void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime)
+{
+ ServiceFlags nLocalNodeServices = pnode->GetLocalServices();
+ uint64_t nonce = pnode->GetLocalNonce();
+ int nNodeStartingHeight = pnode->GetMyStartingHeight();
+ NodeId nodeid = pnode->GetId();
+ CAddress addr = pnode->addr;
+
+ 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,
+ nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes));
+
+ 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);
+ }
+}
+
+void InitializeNode(CNode *pnode, CConnman& connman) {
+ 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 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);
+ }
+ LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
+}
+
+// Requires cs_main.
+// 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) {
+ 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);
+ state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;
+ if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) {
+ // Last validated block on the queue was received.
+ nPeersWithValidatedDownloads--;
+ }
+ if (state->vBlocksInFlight.begin() == itInFlight->second.second) {
+ // First block on the queue was received, update the start download time for the next one
+ state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros());
+ }
+ state->vBlocksInFlight.erase(itInFlight->second.second);
+ state->nBlocksInFlight--;
+ state->nStallingSince = 0;
+ mapBlocksInFlight.erase(itInFlight);
+ return true;
+ }
+ return false;
+}
+
+// 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, std::list<QueuedBlock>::iterator** pit = NULL) {
+ CNodeState *state = State(nodeid);
+ assert(state != NULL);
+
+ // Short-circuit most stuff in case its from the same node
+ 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;
+ return false;
+ }
+
+ // Make sure it's not listed somewhere already.
+ MarkBlockAsReceived(hash);
+
+ std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),
+ {hash, pindex, pindex != NULL, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&mempool) : NULL)});
+ 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) {
+ nPeersWithValidatedDownloads++;
+ }
+ itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it))).first;
+ if (pit)
+ *pit = &itInFlight->second.second;
+ return true;
+}
+
+/** Check whether the last unknown block a peer advertised is not yet known. */
+void ProcessBlockAvailability(NodeId nodeid) {
+ CNodeState *state = State(nodeid);
+ assert(state != NULL);
+
+ 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)
+ state->pindexBestKnownBlock = itOld->second;
+ state->hashLastUnknownBlock.SetNull();
+ }
+ }
+}
+
+/** 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);
+
+ 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)
+ state->pindexBestKnownBlock = it->second;
+ } else {
+ // An unknown block was announced; just assume that the latest one is the best one.
+ state->hashLastUnknownBlock = hash;
+ }
+}
+
+void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) {
+ AssertLockHeld(cs_main);
+ CNodeState* nodestate = State(nodeid);
+ if (!nodestate || !nodestate->fSupportsDesiredCmpctVersion) {
+ // Never ask from peers who can't provide witnesses.
+ return;
+ }
+ if (nodestate->fProvidesHeaderAndIDs) {
+ for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
+ if (*it == nodeid) {
+ lNodesAnnouncingHeaderAndIDs.erase(it);
+ lNodesAnnouncingHeaderAndIDs.push_back(nodeid);
+ return;
+ }
+ }
+ 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));
+ return true;
+ });
+ lNodesAnnouncingHeaderAndIDs.pop_front();
+ }
+ fAnnounceUsingCMPCTBLOCK = true;
+ connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());
+ return true;
+ });
+ }
+}
+
+// Requires cs_main
+bool CanDirectFetch(const Consensus::Params &consensusParams)
+{
+ return chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20;
+}
+
+// Requires cs_main
+bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex)
+{
+ if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight))
+ return true;
+ if (state->pindexBestHeaderSent && pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight))
+ return true;
+ 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) {
+ if (count == 0)
+ return;
+
+ vBlocks.reserve(vBlocks.size() + count);
+ CNodeState *state = State(nodeid);
+ assert(state != NULL);
+
+ // Make sure pindexBestKnownBlock is up to date, we'll need it.
+ ProcessBlockAvailability(nodeid);
+
+ if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) {
+ // This peer has nothing interesting.
+ return;
+ }
+
+ if (state->pindexLastCommonBlock == NULL) {
+ // 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())];
+ }
+
+ // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor
+ // of its current tip anymore. Go back enough to fix that.
+ state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock);
+ if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
+ return;
+
+ std::vector<const CBlockIndex*> vToFetch;
+ const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
+ // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
+ // linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
+ // download that next block if the window were 1 larger.
+ int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW;
+ int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
+ NodeId waitingfor = -1;
+ while (pindexWalk->nHeight < nMaxHeight) {
+ // Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards
+ // pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive
+ // as iterating over ~100 CBlockIndex* entries anyway.
+ int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max<int>(count - vBlocks.size(), 128));
+ vToFetch.resize(nToFetch);
+ pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch);
+ vToFetch[nToFetch - 1] = pindexWalk;
+ for (unsigned int i = nToFetch - 1; i > 0; i--) {
+ vToFetch[i - 1] = vToFetch[i]->pprev;
+ }
+
+ // Iterate over those blocks in vToFetch (in forward direction), adding the ones that
+ // are not yet downloaded and not in flight to vBlocks. In the mean time, update
+ // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's
+ // already part of our chain (and therefore don't need it even if pruned).
+ BOOST_FOREACH(const CBlockIndex* pindex, vToFetch) {
+ if (!pindex->IsValid(BLOCK_VALID_TREE)) {
+ // We consider the chain that this peer is on invalid.
+ return;
+ }
+ if (!State(nodeid)->fHaveWitness && IsWitnessEnabled(pindex->pprev, consensusParams)) {
+ // We wouldn't download this block or its descendants from this peer.
+ return;
+ }
+ if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
+ if (pindex->nChainTx)
+ state->pindexLastCommonBlock = pindex;
+ } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
+ // The block is not already downloaded, and not yet in flight.
+ if (pindex->nHeight > nWindowEnd) {
+ // We reached the end of the window.
+ if (vBlocks.size() == 0 && waitingfor != nodeid) {
+ // We aren't able to fetch anything, but we would be if the download window was one larger.
+ nodeStaller = waitingfor;
+ }
+ return;
+ }
+ vBlocks.push_back(pindex);
+ if (vBlocks.size() == count) {
+ return;
+ }
+ } else if (waitingfor == -1) {
+ // This is the first already-in-flight block.
+ waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first;
+ }
+ }
+ }
+}
+
+} // anon namespace
+
+bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
+ LOCK(cs_main);
+ CNodeState *state = State(nodeid);
+ if (state == NULL)
+ 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) {
+ 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 = 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();
+ if (mapOrphanTransactions.count(hash))
+ return false;
+
+ // Ignore big transactions, to avoid a
+ // send-big-orphans memory exhaustion attack. If a peer has a legitimate
+ // large transaction with a missing parent then we assume
+ // it will rebroadcast it later, after the parent transaction(s)
+ // have been mined or received.
+ // 100 orphans, each of which is at most 99,999 bytes big is
+ // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):
+ unsigned int sz = GetTransactionWeight(*tx);
+ if (sz >= MAX_STANDARD_TX_WEIGHT)
+ {
+ 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) {
+ mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first);
+ }
+
+ 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)
+{
+ std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
+ if (it == mapOrphanTransactions.end())
+ return 0;
+ BOOST_FOREACH(const CTxIn& txin, it->second.tx->vin)
+ {
+ auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout);
+ if (itPrev == mapOrphanTransactionsByPrev.end())
+ continue;
+ itPrev->second.erase(it);
+ if (itPrev->second.empty())
+ mapOrphanTransactionsByPrev.erase(itPrev);
+ }
+ mapOrphanTransactions.erase(it);
+ return 1;
+}
+
+void EraseOrphansFor(NodeId peer)
+{
+ int nErased = 0;
+ std::map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
+ while (iter != mapOrphanTransactions.end())
+ {
+ 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(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer);
+}
+
+
+unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+{
+ unsigned int nEvicted = 0;
+ static int64_t nNextSweep;
+ int64_t nNow = GetTime();
+ if (nNextSweep <= nNow) {
+ // Sweep out expired orphan pool entries:
+ int nErased = 0;
+ int64_t nMinExpTime = nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL;
+ std::map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
+ while (iter != mapOrphanTransactions.end())
+ {
+ std::map<uint256, COrphanTx>::iterator maybeErase = iter++;
+ if (maybeErase->second.nTimeExpire <= nNow) {
+ nErased += EraseOrphanTx(maybeErase->second.tx->GetHash());
+ } else {
+ nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime);
+ }
+ }
+ // 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(BCLog::MEMPOOL, "Erased %d orphan tx due to expiration\n", nErased);
+ }
+ while (mapOrphanTransactions.size() > nMaxOrphans)
+ {
+ // Evict a random orphan:
+ uint256 randomhash = GetRandHash();
+ std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
+ if (it == mapOrphanTransactions.end())
+ it = mapOrphanTransactions.begin();
+ EraseOrphanTx(it->first);
+ ++nEvicted;
+ }
+ return nEvicted;
+}
+
+// Requires cs_main.
+void Misbehaving(NodeId pnode, int howmuch)
+{
+ if (howmuch == 0)
+ return;
+
+ CNodeState *state = State(pnode);
+ if (state == NULL)
+ return;
+
+ state->nMisbehavior += howmuch;
+ int banscore = 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);
+ state->fShouldBan = true;
+ } else
+ LogPrintf("%s: %s peer=%d (%d -> %d)\n", __func__, state->name, pnode, state->nMisbehavior-howmuch, state->nMisbehavior);
+}
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// blockchain -> download logic notification
+//
+
+PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn) : connman(connmanIn) {
+ // Initialize global variables that cannot be constructed at startup.
+ recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
+}
+
+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;
+
+ for (const CTransactionRef& ptx : pblock->vtx) {
+ const CTransaction& tx = *ptx;
+
+ // 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);
+ }
+ }
+ }
+
+ // Erase orphan transactions include or precluded by this block
+ if (vOrphanErase.size()) {
+ int nErased = 0;
+ BOOST_FOREACH(uint256 &orphanHash, vOrphanErase) {
+ nErased += EraseOrphanTx(orphanHash);
+ }
+ 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);
+ const CNetMsgMaker msgMaker(PROTOCOL_VERSION);
+
+ LOCK(cs_main);
+
+ static int nHighestFastAnnounce = 0;
+ if (pindex->nHeight <= nHighestFastAnnounce)
+ return;
+ nHighestFastAnnounce = pindex->nHeight;
+
+ bool fWitnessEnabled = IsWitnessEnabled(pindex->pprev, Params().GetConsensus());
+ uint256 hashBlock(pblock->GetHash());
+
+ {
+ LOCK(cs_most_recent_block);
+ 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) {
+ // TODO: Avoid the repeated-serialization here
+ if (pnode->nVersion < INVALID_CB_NO_BAN_VERSION || pnode->fDisconnect)
+ return;
+ ProcessBlockAvailability(pnode->GetId());
+ CNodeState &state = *State(pnode->GetId());
+ // If the peer has, or we announced to them the previous block already,
+ // but we don't think they have this one, go ahead and announce it
+ if (state.fPreferHeaderAndIDs && (!fWitnessEnabled || state.fWantsCmpctWitness) &&
+ !PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->pprev)) {
+
+ 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;
+ }
+ });
+}
+
+void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
+ const int nNewHeight = pindexNew->nHeight;
+ connman->SetBestHeight(nNewHeight);
+
+ if (!fInitialDownload) {
+ // Find the hashes of all blocks that weren't previously in the best chain.
+ std::vector<uint256> vHashes;
+ const CBlockIndex *pindexToAnnounce = pindexNew;
+ while (pindexToAnnounce != pindexFork) {
+ vHashes.push_back(pindexToAnnounce->GetBlockHash());
+ pindexToAnnounce = pindexToAnnounce->pprev;
+ if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) {
+ // Limit announcements in case of a huge reorganization.
+ // Rely on the peer's synchronization mechanism in that case.
+ break;
+ }
+ }
+ // Relay inventory, but don't relay old inventory during initial block download.
+ connman->ForEachNode([nNewHeight, &vHashes](CNode* pnode) {
+ if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 0)) {
+ BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
+ pnode->PushBlockHash(hash);
+ }
+ }
+ });
+ connman->WakeMessageHandler();
+ }
+
+ nTimeBestReceived = GetTime();
+}
+
+void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state) {
+ LOCK(cs_main);
+
+ const uint256 hash(block.GetHash());
+ std::map<uint256, std::pair<NodeId, bool>>::iterator it = mapBlockSource.find(hash);
+
+ int nDoS = 0;
+ if (state.IsInvalid(nDoS)) {
+ // 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);
+ }
+ }
+ // 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);
+ }
+ }
+ if (it != mapBlockSource.end())
+ mapBlockSource.erase(it);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Messages
+//
+
+
+bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+{
+ switch (inv.type)
+ {
+ case MSG_TX:
+ case MSG_WITNESS_TX:
+ {
+ assert(recentRejects);
+ if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip)
+ {
+ // If the chain tip has changed previously rejected transactions
+ // might be now valid, e.g. due to a nLockTime'd tx becoming valid,
+ // or a double-spend. Reset the rejects filter and give those
+ // txs a second chance.
+ hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash();
+ recentRejects->reset();
+ }
+
+ // 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);
+ }
+ case MSG_BLOCK:
+ case MSG_WITNESS_BLOCK:
+ return mapBlockIndex.count(inv.hash);
+ }
+ // Don't know what it is, just say we already got one
+ return true;
+}
+
+static void RelayTransaction(const CTransaction& tx, CConnman& connman)
+{
+ CInv inv(MSG_TX, tx.GetHash());
+ connman.ForEachNode([&inv](CNode* pnode)
+ {
+ pnode->PushInventory(inv);
+ });
+}
+
+static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman)
+{
+ unsigned int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
+
+ // Relay to a limited number of other nodes
+ // 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));
+ FastRandomContext insecure_rand;
+
+ std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};
+ assert(nRelayNodes <= best.size());
+
+ auto sortfunc = [&best, &hasher, nRelayNodes](CNode* pnode) {
+ if (pnode->nVersion >= CADDR_TIME_VERSION) {
+ 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);
+ best[i] = std::make_pair(hashKey, pnode);
+ break;
+ }
+ }
+ }
+ };
+
+ auto pushfunc = [&addr, &best, nRelayNodes, &insecure_rand] {
+ for (unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
+ best[i].second->PushAddress(addr, insecure_rand);
+ }
+ };
+
+ connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
+}
+
+void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman, const std::atomic<bool>& interruptMsgProc)
+{
+ std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
+ std::vector<CInv> vNotFound;
+ const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
+ LOCK(cs_main);
+
+ while (it != pfrom->vRecvGetData.end()) {
+ // Don't bother if send buffer is too full to respond anyway
+ if (pfrom->fPauseSend)
+ break;
+
+ const CInv &inv = *it;
+ {
+ if (interruptMsgProc)
+ return;
+
+ it++;
+
+ if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK)
+ {
+ 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) &&
+ mi->second->IsValid(BLOCK_VALID_TREE)) {
+ // If we have the block and all of its parents, but have not yet validated it,
+ // we might be in the middle of connecting it (ie in the unlock of cs_main
+ // before ActivateBestChain but after AcceptBlock).
+ // In this case, we need to run ActivateBestChain prior to checking the relay
+ // conditions below.
+ CValidationState dummy;
+ ActivateBestChain(dummy, Params(), a_recent_block);
+ }
+ if (chainActive.Contains(mi->second)) {
+ send = true;
+ } else {
+ static const int nOneMonth = 30 * 24 * 60 * 60;
+ // 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) &&
+ (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) &&
+ (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensusParams) < nOneMonth);
+ if (!send) {
+ LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId());
+ }
+ }
+ }
+ // 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)
+ {
+ LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
+
+ //disconnect node
+ pfrom->fDisconnect = true;
+ send = false;
+ }
+ // Pruned nodes may have deleted the block, so check whether
+ // it's available before trying to send.
+ if (send && (mi->second->nStatus & BLOCK_HAVE_DATA))
+ {
+ 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, *pblock));
+ else if (inv.type == MSG_WITNESS_BLOCK)
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
+ else if (inv.type == MSG_FILTERED_BLOCK)
+ {
+ bool sendMerkleBlock = false;
+ CMerkleBlock merkleBlock;
+ {
+ LOCK(pfrom->cs_filter);
+ if (pfrom->pfilter) {
+ sendMerkleBlock = true;
+ merkleBlock = CMerkleBlock(*pblock, *pfrom->pfilter);
+ }
+ }
+ if (sendMerkleBlock) {
+ 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 -
+ // they must either disconnect and retry or request the full block.
+ // 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, *pblock->vtx[pair.first]));
+ }
+ // else
+ // no response
+ }
+ else if (inv.type == MSG_CMPCT_BLOCK)
+ {
+ // If a peer is asking for old blocks, we're almost guaranteed
+ // they won't have a useful mempool to match against a compact block,
+ // and we don't feel like constructing the object for them, so
+ // instead we respond with the full, non-compact block.
+ 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) {
+ 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
+ if (inv.hash == pfrom->hashContinue)
+ {
+ // 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.
+ std::vector<CInv> vInv;
+ vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash()));
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv));
+ pfrom->hashContinue.SetNull();
+ }
+ }
+ }
+ else if (inv.type == MSG_TX || inv.type == MSG_WITNESS_TX)
+ {
+ // Send stream from relay memory
+ bool push = false;
+ 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));
+ 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));
+ push = true;
+ }
+ }
+ if (!push) {
+ vNotFound.push_back(inv);
+ }
+ }
+
+ // Track requests for our stuff.
+ GetMainSignals().Inventory(inv.hash);
+
+ if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK)
+ break;
+ }
+ }
+
+ pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it);
+
+ if (!vNotFound.empty()) {
+ // Let the peer know that we didn't find what it asked for, so it doesn't
+ // have to wait around forever. Currently only SPV clients actually care
+ // about this message: it's needed when they are recursively walking the
+ // dependencies of relevant unconfirmed transactions. SPV clients want to
+ // 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));
+ }
+}
+
+uint32_t GetFetchFlags(CNode* pfrom) {
+ uint32_t nFetchFlags = 0;
+ if ((pfrom->GetLocalServices() & NODE_WITNESS) && State(pfrom->GetId())->fHaveWitness) {
+ nFetchFlags |= MSG_WITNESS_FLAG;
+ }
+ return nFetchFlags;
+}
+
+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->GetId());
+ return;
+ }
+ resp.txn[i] = block.vtx[req.indexes[i]];
+ }
+ LOCK(cs_main);
+ 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));
+}
+
+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(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId());
+ if (IsArgSet("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 0)) == 0)
+ {
+ LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n");
+ return true;
+ }
+
+
+ if (!(pfrom->GetLocalServices() & NODE_BLOOM) &&
+ (strCommand == NetMsgType::FILTERLOAD ||
+ strCommand == NetMsgType::FILTERADD))
+ {
+ if (pfrom->nVersion >= NO_BLOOM_VERSION) {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 100);
+ return false;
+ } else {
+ pfrom->fDisconnect = true;
+ return false;
+ }
+ }
+
+ 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 (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, std::string("Duplicate version message")));
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 1);
+ return false;
+ }
+
+ int64_t nTime;
+ CAddress addrMe;
+ CAddress addrFrom;
+ uint64_t nNonce = 1;
+ uint64_t 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, nServices);
+ }
+ if (pfrom->nServicesExpected & ~nServices)
+ {
+ 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 (nVersion < MIN_PEER_PROTO_VERSION)
+ {
+ // disconnect from peers older than this proto version
+ 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 (nVersion == 10300)
+ nVersion = 300;
+ if (!vRecv.empty())
+ vRecv >> addrFrom >> nNonce;
+ if (!vRecv.empty()) {
+ vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH);
+ cleanSubVer = SanitizeString(strSubVer);
+ }
+ if (!vRecv.empty()) {
+ vRecv >> nStartingHeight;
+ }
+ if (!vRecv.empty())
+ vRecv >> fRelay;
+ // Disconnect if we connected to ourself
+ if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce))
+ {
+ LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString());
+ pfrom->fDisconnect = true;
+ return true;
+ }
+
+ if (pfrom->fInbound && addrMe.IsRoutable())
+ {
+ SeenLocal(addrMe);
+ }
+
+ // Be shy and don't send version until we hear
+ if (pfrom->fInbound)
+ PushNodeVersion(pfrom, connman, GetAdjustedTime());
+
+ connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
+
+ 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;
+ }
+
+ // Potentially mark this peer as a preferred download peer.
+ {
+ LOCK(cs_main);
+ UpdatePreferredDownload(pfrom, State(pfrom->GetId()));
+ }
+
+ if (!pfrom->fInbound)
+ {
+ // Advertise our address
+ if (fListen && !IsInitialBlockDownload())
+ {
+ CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
+ FastRandomContext insecure_rand;
+ if (addr.IsRoutable())
+ {
+ LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
+ pfrom->PushAddress(addr, insecure_rand);
+ } else if (IsPeerAddrLocalGood(pfrom)) {
+ 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)
+ {
+ connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));
+ pfrom->fGetAddr = true;
+ }
+ connman.MarkAddressGood(pfrom->addr);
+ }
+
+ 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",
+ 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);
+ pfrom->fDisconnect = true;
+ }
+ return true;
+ }
+
+
+ else if (pfrom->nVersion == 0)
+ {
+ // Must have a version message before anything else
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 1);
+ return false;
+ }
+
+ // At this point, the outgoing message serialization version can't change.
+ const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
+
+ if (strCommand == NetMsgType::VERACK)
+ {
+ pfrom->SetRecvVersion(std::min(pfrom->nVersion.load(), PROTOCOL_VERSION));
+
+ if (!pfrom->fInbound) {
+ // Mark this node as currently connected, so we update its timestamp later.
+ LOCK(cs_main);
+ State(pfrom->GetId())->fCurrentlyConnected = true;
+ }
+
+ if (pfrom->nVersion >= SENDHEADERS_VERSION) {
+ // Tell our peer we prefer to receive headers rather than inv's
+ // 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));
+ }
+ if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) {
+ // Tell our peer we are willing to provide version 1 or 2 cmpctblocks
+ // However, we do not request new block announcements using
+ // cmpctblock messages.
+ // We send this to non-NODE NETWORK peers as well, because
+ // they may wish to request compact blocks from us
+ bool fAnnounceUsingCMPCTBLOCK = false;
+ uint64_t nCMPCTBLOCKVersion = 2;
+ if (pfrom->GetLocalServices() & NODE_WITNESS)
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ nCMPCTBLOCKVersion = 1;
+ 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)
+ {
+ std::vector<CAddress> vAddr;
+ vRecv >> vAddr;
+
+ // Don't want addr from older versions unless seeding
+ if (pfrom->nVersion < CADDR_TIME_VERSION && connman.GetAddressCount() > 1000)
+ return true;
+ if (vAddr.size() > 1000)
+ {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 20);
+ return error("message addr size() = %u", vAddr.size());
+ }
+
+ // Store the new addresses
+ std::vector<CAddress> vAddrOk;
+ int64_t nNow = GetAdjustedTime();
+ int64_t nSince = nNow - 10 * 60;
+ BOOST_FOREACH(CAddress& addr, vAddr)
+ {
+ if (interruptMsgProc)
+ return true;
+
+ if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)
+ continue;
+
+ if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
+ addr.nTime = nNow - 5 * 24 * 60 * 60;
+ pfrom->AddAddressKnown(addr);
+ bool fReachable = IsReachable(addr);
+ if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
+ {
+ // Relay to a limited number of other nodes
+ RelayAddress(addr, fReachable, connman);
+ }
+ // Do not store addresses outside our network
+ if (fReachable)
+ vAddrOk.push_back(addr);
+ }
+ connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60);
+ if (vAddr.size() < 1000)
+ pfrom->fGetAddr = false;
+ if (pfrom->fOneShot)
+ pfrom->fDisconnect = true;
+ }
+
+ else if (strCommand == NetMsgType::SENDHEADERS)
+ {
+ LOCK(cs_main);
+ State(pfrom->GetId())->fPreferHeaders = true;
+ }
+
+ else if (strCommand == NetMsgType::SENDCMPCT)
+ {
+ bool fAnnounceUsingCMPCTBLOCK = false;
+ uint64_t nCMPCTBLOCKVersion = 0;
+ vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
+ if (nCMPCTBLOCKVersion == 1 || ((pfrom->GetLocalServices() & NODE_WITNESS) && nCMPCTBLOCKVersion == 2)) {
+ LOCK(cs_main);
+ // fProvidesHeaderAndIDs is used to "lock in" version of compact blocks we send (fWantsCmpctWitness)
+ if (!State(pfrom->GetId())->fProvidesHeaderAndIDs) {
+ State(pfrom->GetId())->fProvidesHeaderAndIDs = true;
+ State(pfrom->GetId())->fWantsCmpctWitness = nCMPCTBLOCKVersion == 2;
+ }
+ if (State(pfrom->GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2)) // ignore later version announces
+ State(pfrom->GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK;
+ if (!State(pfrom->GetId())->fSupportsDesiredCmpctVersion) {
+ if (pfrom->GetLocalServices() & NODE_WITNESS)
+ State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2);
+ else
+ State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1);
+ }
+ }
+ }
+
+
+ else if (strCommand == NetMsgType::INV)
+ {
+ std::vector<CInv> vInv;
+ vRecv >> vInv;
+ if (vInv.size() > MAX_INV_SZ)
+ {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 20);
+ return error("message inv size() = %u", vInv.size());
+ }
+
+ 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))
+ fBlocksOnly = false;
+
+ LOCK(cs_main);
+
+ uint32_t nFetchFlags = GetFetchFlags(pfrom);
+
+ for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
+ {
+ CInv &inv = vInv[nInv];
+
+ if (interruptMsgProc)
+ return true;
+
+ bool fAlreadyHave = AlreadyHave(inv);
+ 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;
+ }
+
+ if (inv.type == MSG_BLOCK) {
+ UpdateBlockAvailability(pfrom->GetId(), inv.hash);
+ if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
+ // We used to request the full block here, but since headers-announcements are now the
+ // primary method of announcement on the network, and since, in the case that a node
+ // 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(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId());
+ }
+ }
+ else
+ {
+ pfrom->AddInventoryKnown(inv);
+ 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);
+ }
+ }
+
+
+ else if (strCommand == NetMsgType::GETDATA)
+ {
+ std::vector<CInv> vInv;
+ vRecv >> vInv;
+ if (vInv.size() > MAX_INV_SZ)
+ {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 20);
+ return error("message getdata size() = %u", vInv.size());
+ }
+
+ LogPrint(BCLog::NET, "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom->GetId());
+
+ 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);
+ }
+
+
+ else if (strCommand == NetMsgType::GETBLOCKS)
+ {
+ CBlockLocator locator;
+ uint256 hashStop;
+ vRecv >> locator >> hashStop;
+
+ // We might have announced the currently-being-connected tip using a
+ // compact block, which resulted in the peer sending a getblocks
+ // request, which we would otherwise respond to without the new block.
+ // To avoid this situation we simply verify that we are on our best
+ // known chain now. This is super overkill, but we handle it better
+ // for getheaders requests, and there are no known nodes which support
+ // compact blocks but still use getblocks to request blocks.
+ {
+ 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);
+ }
+
+ LOCK(cs_main);
+
+ // Find the last block the caller has in the main chain
+ const CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator);
+
+ // Send the rest of the chain
+ if (pindex)
+ pindex = chainActive.Next(pindex);
+ int nLimit = 500;
+ 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(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
+ // for some reasonable time window (1 hour) that block relay might require.
+ 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(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()));
+ if (--nLimit <= 0)
+ {
+ // When this block is requested, we'll send an inv that'll
+ // trigger the peer to getblocks the next batch of inventory.
+ LogPrint(BCLog::NET, " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ pfrom->hashContinue = pindex->GetBlockHash();
+ break;
+ }
+ }
+ }
+
+
+ else if (strCommand == NetMsgType::GETBLOCKTXN)
+ {
+ BlockTransactionsRequest req;
+ vRecv >> req;
+
+ std::shared_ptr<const CBlock> recent_block;
+ {
+ LOCK(cs_most_recent_block);
+ if (most_recent_block_hash == req.blockhash)
+ recent_block = most_recent_block;
+ // Unlock cs_most_recent_block to avoid cs_main lock inversion
+ }
+ if (recent_block) {
+ SendBlockTransactions(*recent_block, req, pfrom, connman);
+ return true;
+ }
+
+ LOCK(cs_main);
+
+ 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->GetId());
+ return true;
+ }
+
+ if (it->second->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) {
+ // If an older block is requested (should never happen in practice,
+ // but can happen in tests) send a block response instead of a
+ // blocktxn response. Sending a full block response instead of a
+ // small blocktxn response is preferable in the case where a peer
+ // 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(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;
+ pfrom->vRecvGetData.push_back(inv);
+ ProcessGetData(pfrom, chainparams.GetConsensus(), connman, interruptMsgProc);
+ return true;
+ }
+
+ CBlock block;
+ bool ret = ReadBlockFromDisk(block, it->second, chainparams.GetConsensus());
+ assert(ret);
+
+ SendBlockTransactions(block, req, pfrom, connman);
+ }
+
+
+ else if (strCommand == NetMsgType::GETHEADERS)
+ {
+ CBlockLocator locator;
+ uint256 hashStop;
+ vRecv >> locator >> hashStop;
+
+ LOCK(cs_main);
+ if (IsInitialBlockDownload() && !pfrom->fWhitelisted) {
+ 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;
+ if (locator.IsNull())
+ {
+ // If locator is null, return the hashStop block
+ BlockMap::iterator mi = mapBlockIndex.find(hashStop);
+ if (mi == mapBlockIndex.end())
+ return true;
+ pindex = (*mi).second;
+ }
+ else
+ {
+ // Find the last block the caller has in the main chain
+ pindex = FindForkInGlobalIndex(chainActive, locator);
+ if (pindex)
+ pindex = chainActive.Next(pindex);
+ }
+
+ // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
+ std::vector<CBlock> vHeaders;
+ int nLimit = MAX_HEADERS_RESULTS;
+ 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
+ // 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.
+ //
+ // It is important that we simply reset the BestHeaderSent value here,
+ // and not max(BestHeaderSent, newHeaderSent). We might have announced
+ // the currently-being-connected tip using a compact block, which
+ // resulted in the peer sending a headers request, which we respond to
+ // without the new block. By resetting the BestHeaderSent, we ensure we
+ // 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));
+ }
+
+
+ else if (strCommand == NetMsgType::TX)
+ {
+ // 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)))
+ {
+ LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId());
+ return true;
+ }
+
+ std::deque<COutPoint> vWorkQueue;
+ std::vector<uint256> vEraseQueue;
+ CTransactionRef ptx;
+ vRecv >> ptx;
+ const CTransaction& tx = *ptx;
+
+ CInv inv(MSG_TX, tx.GetHash());
+ pfrom->AddInventoryKnown(inv);
+
+ LOCK(cs_main);
+
+ bool fMissingInputs = false;
+ CValidationState state;
+
+ pfrom->setAskFor.erase(inv.hash);
+ mapAlreadyAskedFor.erase(inv.hash);
+
+ std::list<CTransactionRef> lRemovedTxn;
+
+ if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, ptx, true, &fMissingInputs, &lRemovedTxn)) {
+ mempool.check(pcoinsTip);
+ RelayTransaction(tx, connman);
+ for (unsigned int i = 0; i < tx.vout.size(); i++) {
+ vWorkQueue.emplace_back(inv.hash, i);
+ }
+
+ pfrom->nLastTXTime = GetTime();
+
+ 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
+ std::set<NodeId> setMisbehaving;
+ while (!vWorkQueue.empty()) {
+ auto itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue.front());
+ vWorkQueue.pop_front();
+ if (itByPrev == mapOrphanTransactionsByPrev.end())
+ continue;
+ for (auto mi = itByPrev->second.begin();
+ mi != itByPrev->second.end();
+ ++mi)
+ {
+ const CTransactionRef& porphanTx = (*mi)->second.tx;
+ const CTransaction& orphanTx = *porphanTx;
+ const uint256& orphanHash = orphanTx.GetHash();
+ NodeId fromPeer = (*mi)->second.fromPeer;
+ bool fMissingInputs2 = false;
+ // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
+ // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
+ // anyone relaying LegitTxX banned)
+ CValidationState stateDummy;
+
+
+ if (setMisbehaving.count(fromPeer))
+ continue;
+ if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, true, &fMissingInputs2, &lRemovedTxn)) {
+ 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);
+ }
+ vEraseQueue.push_back(orphanHash);
+ }
+ else if (!fMissingInputs2)
+ {
+ int nDos = 0;
+ if (stateDummy.IsInvalid(nDos) && nDos > 0)
+ {
+ // Punish peer that gave us an invalid orphan tx
+ Misbehaving(fromPeer, nDos);
+ setMisbehaving.insert(fromPeer);
+ LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
+ }
+ // Has inputs but not accepted to mempool
+ // 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
+ // witness-stripped transactions, as they can have been malleated.
+ // See https://github.com/bitcoin/bitcoin/issues/8279 for details.
+ assert(recentRejects);
+ recentRejects->insert(orphanHash);
+ }
+ }
+ mempool.check(pcoinsTip);
+ }
+ }
+
+ BOOST_FOREACH(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) {
+ if (recentRejects->contains(txin.prevout.hash)) {
+ fRejectedParents = true;
+ break;
+ }
+ }
+ if (!fRejectedParents) {
+ uint32_t nFetchFlags = GetFetchFlags(pfrom);
+ BOOST_FOREACH(const CTxIn& txin, tx.vin) {
+ CInv _inv(MSG_TX | nFetchFlags, txin.prevout.hash);
+ pfrom->AddInventoryKnown(_inv);
+ if (!AlreadyHave(_inv)) pfrom->AskFor(_inv);
+ }
+ 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 nEvicted = LimitOrphanTxSize(nMaxOrphanTx);
+ if (nEvicted > 0) {
+ LogPrint(BCLog::MEMPOOL, "mapOrphan overflow, removed %u tx\n", nEvicted);
+ }
+ } else {
+ 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());
+ }
+ } else {
+ if (!tx.HasWitness() && !state.CorruptionPossible()) {
+ // Do not use rejection cache for witness transactions or
+ // witness-stripped transactions, as they can have been malleated.
+ // 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)) {
+ // 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
+ // nodes hidden behind it.
+ //
+ // Never relay transactions that we would assign a non-zero DoS
+ // score for, as we expect peers to do the same with us in that
+ // case.
+ int nDoS = 0;
+ if (!state.IsInvalid(nDoS) || nDoS == 0) {
+ 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->GetId(), FormatStateMessage(state));
+ }
+ }
+ }
+
+ for (const CTransactionRef& removedTx : lRemovedTxn)
+ AddToCompactExtraTransactions(removedTx);
+
+ int nDoS = 0;
+ if (state.IsInvalid(nDoS))
+ {
+ LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
+ pfrom->GetId(),
+ FormatStateMessage(state));
+ 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);
+ }
+ }
+ }
+
+
+ else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
+ {
+ CBlockHeaderAndShortTxIDs cmpctblock;
+ vRecv >> cmpctblock;
+
+ {
+ LOCK(cs_main);
+
+ 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()));
+ return true;
+ }
+ }
+
+ const CBlockIndex *pindex = NULL;
+ CValidationState state;
+ if (!ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
+ int nDoS;
+ if (state.IsInvalid(nDoS)) {
+ if (nDoS > 0) {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), nDoS);
+ }
+ LogPrintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId());
+ return true;
+ }
+ }
+
+ // When we succeed in decoding a block's txids from a cmpctblock
+ // message we typically jump to the BLOCKTXN handling code, with a
+ // dummy (empty) BLOCKTXN message, to re-use the logic there in
+ // completing processing of the putative block (without cs_main).
+ bool fProcessBLOCKTXN = false;
+ CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
+
+ // If we end up treating this as a plain headers message, call that as well
+ // without cs_main.
+ bool fRevertToHeaderProcessing = false;
+ CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);
+
+ // Keep a CBlock for "optimistic" compactblock reconstructions (see
+ // below)
+ std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
+ bool fBlockReconstructed = false;
+
+ {
+ LOCK(cs_main);
+ // If AcceptBlockHeader returned true, it set pindex
+ assert(pindex);
+ UpdateBlockAvailability(pfrom->GetId(), 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
+ return true;
+
+ if (pindex->nChainWork <= chainActive.Tip()->nChainWork || // We know something better
+ pindex->nTx != 0) { // We had this block at some point, but pruned it
+ if (fAlreadyInFlight) {
+ // 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), cmpctblock.header.GetHash());
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ }
+ return true;
+ }
+
+ // If we're not close to tip yet, give up and let parallel block fetch work its magic
+ if (!fAlreadyInFlight && !CanDirectFetch(chainparams.GetConsensus()))
+ return true;
+
+ CNodeState *nodestate = State(pfrom->GetId());
+
+ if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus()) && !nodestate->fSupportsDesiredCmpctVersion) {
+ // Don't bother trying to process compact blocks from v1 peers
+ // after segwit activates.
+ return true;
+ }
+
+ // We want to be a bit conservative just to be extra careful about DoS
+ // possibilities in compact block processing...
+ if (pindex->nHeight <= chainActive.Height() + 2) {
+ if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
+ (fAlreadyInFlight && blockInFlightIt->second.first == pfrom->GetId())) {
+ std::list<QueuedBlock>::iterator* queuedBlockIt = NULL;
+ if (!MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), chainparams.GetConsensus(), 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(BCLog::NET, "Peer sent us compact block we were already syncing!\n");
+ return true;
+ }
+ }
+
+ PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
+ 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->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), cmpctblock.header.GetHash());
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ return true;
+ }
+
+ BlockTransactionsRequest req;
+ for (size_t i = 0; i < cmpctblock.BlockTxCount(); i++) {
+ if (!partialBlock.IsTxAvailable(i))
+ req.indexes.push_back(i);
+ }
+ if (req.indexes.empty()) {
+ // Dirty hack to jump to BLOCKTXN code (TODO: move message handling into their own functions)
+ BlockTransactions txn;
+ txn.blockhash = cmpctblock.header.GetHash();
+ blockTxnMsg << txn;
+ fProcessBLOCKTXN = true;
+ } else {
+ req.blockhash = pindex->GetBlockHash();
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
+ }
+ } else {
+ // This block is either already in flight from a different
+ // peer, or this peer has too many blocks outstanding to
+ // download from.
+ // Optimistically try to reconstruct anyway since we might be
+ // able to without any round trips.
+ PartiallyDownloadedBlock tempBlock(&mempool);
+ ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
+ if (status != READ_STATUS_OK) {
+ // TODO: don't ignore failures
+ return true;
+ }
+ std::vector<CTransactionRef> dummy;
+ status = tempBlock.FillBlock(*pblock, dummy);
+ if (status == READ_STATUS_OK) {
+ fBlockReconstructed = true;
+ }
+ }
+ } else {
+ if (fAlreadyInFlight) {
+ // 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), 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
+ // Dirty hack to process as if it were just a headers message (TODO: move message handling into their own functions)
+ std::vector<CBlock> headers;
+ headers.push_back(cmpctblock.header);
+ vHeadersMsg << headers;
+ fRevertToHeaderProcessing = true;
+ }
+ }
+ } // cs_main
+
+ if (fProcessBLOCKTXN)
+ return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc);
+
+ if (fRevertToHeaderProcessing)
+ return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman, interruptMsgProc);
+
+ if (fBlockReconstructed) {
+ // If we got here, we were able to optimistically reconstruct a
+ // block that is in flight from some other peer.
+ {
+ LOCK(cs_main);
+ mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom->GetId(), false));
+ }
+ bool fNewBlock = false;
+ ProcessNewBlock(chainparams, pblock, true, &fNewBlock);
+ if (fNewBlock)
+ pfrom->nLastBlockTime = GetTime();
+
+ LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid()
+ if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) {
+ // Clear download state for this block, which is in
+ // process from some other peer. We do this after calling
+ // ProcessNewBlock so that a malleated cmpctblock announcement
+ // can't be used to interfere with block relay.
+ MarkBlockAsReceived(pblock->GetHash());
+ }
+ }
+
+ }
+
+ else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing
+ {
+ BlockTransactions resp;
+ vRecv >> resp;
+
+ std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
+ bool fBlockRead = false;
+ {
+ LOCK(cs_main);
+
+ 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(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom->GetId());
+ return true;
+ }
+
+ PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock;
+ ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn);
+ 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->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), resp.blockhash));
+ connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
+ } else {
+ // Block is either okay, or possibly we received
+ // READ_STATUS_CHECKBLOCK_FAILED.
+ // Note that CheckBlock can only fail for one of a few reasons:
+ // 1. bad-proof-of-work (impossible here, because we've already
+ // accepted the header)
+ // 2. merkleroot doesn't match the transactions given (already
+ // caught in FillBlock with READ_STATUS_FAILED, so
+ // impossible here)
+ // 3. the block is otherwise invalid (eg invalid coinbase,
+ // block is too big, too many legacy sigops, etc).
+ // So if CheckBlock failed, #3 is the only possibility.
+ // Under BIP 152, we don't DoS-ban unless proof of work is
+ // invalid (we don't require all the stateless checks to have
+ // been run). This is handled below, so just treat this as
+ // though the block was successfully read, and rely on the
+ // handling in ProcessNewBlock to ensure the block index is
+ // updated, reject messages go out, etc.
+ MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
+ fBlockRead = true;
+ // mapBlockSource is only used for sending reject messages and DoS scores,
+ // so the race between here and cs_main in ProcessNewBlock is fine.
+ // BIP 152 permits peers to relay compact blocks after validating
+ // the header only; we should not punish peers if the block turns
+ // out to be invalid.
+ mapBlockSource.emplace(resp.blockhash, std::make_pair(pfrom->GetId(), false));
+ }
+ } // Don't hold cs_main when we call into ProcessNewBlock
+ if (fBlockRead) {
+ bool fNewBlock = false;
+ // 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)
+ pfrom->nLastBlockTime = GetTime();
+ }
+ }
+
+
+ else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing
+ {
+ std::vector<CBlockHeader> headers;
+
+ // Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
+ unsigned int nCount = ReadCompactSize(vRecv);
+ if (nCount > MAX_HEADERS_RESULTS) {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 20);
+ return error("headers message size = %u", nCount);
+ }
+ headers.resize(nCount);
+ for (unsigned int n = 0; n < nCount; n++) {
+ vRecv >> headers[n];
+ ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
+ }
+
+ if (nCount == 0) {
+ // Nothing interesting. Stop asking this peers for more headers.
+ return true;
+ }
+
+ const CBlockIndex *pindexLast = NULL;
+ {
+ LOCK(cs_main);
+ CNodeState *nodestate = State(pfrom->GetId());
+
+ // If this looks like it could be a block announcement (nCount <
+ // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
+ // don't connect:
+ // - Send a getheaders message in response to try to connect the chain.
+ // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
+ // don't connect before giving DoS points
+ // - Once a headers message is received that is valid and does connect,
+ // 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(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->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.
+ UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash());
+
+ if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
+ Misbehaving(pfrom->GetId(), 20);
+ }
+ return true;
+ }
+
+ uint256 hashLastBlock;
+ for (const CBlockHeader& header : headers) {
+ if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) {
+ Misbehaving(pfrom->GetId(), 20);
+ return error("non-continuous headers sequence");
+ }
+ hashLastBlock = header.GetHash();
+ }
+ }
+
+ CValidationState state;
+ if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) {
+ int nDoS;
+ if (state.IsInvalid(nDoS)) {
+ if (nDoS > 0) {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), nDoS);
+ }
+ return error("invalid header received");
+ }
+ }
+
+ {
+ LOCK(cs_main);
+ CNodeState *nodestate = State(pfrom->GetId());
+ if (nodestate->nUnconnectingHeaders > 0) {
+ LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->GetId(), nodestate->nUnconnectingHeaders);
+ }
+ nodestate->nUnconnectingHeaders = 0;
+
+ assert(pindexLast);
+ UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
+
+ if (nCount == MAX_HEADERS_RESULTS) {
+ // 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(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) {
+ 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) {
+ if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
+ !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
+ (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
+ // We don't have this block, and it's not yet in flight.
+ vToFetch.push_back(pindexWalk);
+ }
+ pindexWalk = pindexWalk->pprev;
+ }
+ // If pindexWalk still isn't on our main chain, we're looking at a
+ // very large reorg at a time we think we're close to caught up to
+ // 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(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n",
+ pindexLast->GetBlockHash().ToString(),
+ pindexLast->nHeight);
+ } else {
+ std::vector<CInv> vGetData;
+ // Download as much as possible, from earliest to latest.
+ BOOST_REVERSE_FOREACH(const CBlockIndex *pindex, vToFetch) {
+ if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ // Can't download any more from this peer
+ break;
+ }
+ uint32_t nFetchFlags = GetFetchFlags(pfrom);
+ vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
+ MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), chainparams.GetConsensus(), pindex);
+ LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n",
+ pindex->GetBlockHash().ToString(), pfrom->GetId());
+ }
+ if (vGetData.size() > 1) {
+ LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n",
+ pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
+ }
+ if (vGetData.size() > 0) {
+ if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) {
+ // 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));
+ }
+ }
+ }
+ }
+ }
+
+ else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
+ {
+ std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
+ vRecv >> *pblock;
+
+ 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.
+ // Such an unrequested block may still be processed, subject to the
+ // conditions in AcceptBlock().
+ bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
+ const uint256 hash(pblock->GetHash());
+ {
+ LOCK(cs_main);
+ // Also always process if we requested the block explicitly, as we may
+ // need it even though it is not a candidate for a new best tip.
+ forceProcessing |= MarkBlockAsReceived(hash);
+ // mapBlockSource is only used for sending reject messages and DoS scores,
+ // so the race between here and cs_main in ProcessNewBlock is fine.
+ mapBlockSource.emplace(hash, std::make_pair(pfrom->GetId(), true));
+ }
+ bool fNewBlock = false;
+ ProcessNewBlock(chainparams, pblock, forceProcessing, &fNewBlock);
+ if (fNewBlock)
+ pfrom->nLastBlockTime = GetTime();
+ }
+
+
+ else if (strCommand == NetMsgType::GETADDR)
+ {
+ // This asymmetric behavior for inbound and outbound connections was introduced
+ // to prevent a fingerprinting attack: an attacker can send specific fake addresses
+ // to users' AddrMan and later request them by sending getaddr messages.
+ // Making nodes which are behind NAT and can only make outgoing connections ignore
+ // the getaddr message mitigates the attack.
+ if (!pfrom->fInbound) {
+ 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(BCLog::NET, "Ignoring repeated \"getaddr\". peer=%d\n", pfrom->GetId());
+ return true;
+ }
+ pfrom->fSentAddr = true;
+
+ pfrom->vAddrToSend.clear();
+ std::vector<CAddress> vAddr = connman.GetAddresses();
+ FastRandomContext insecure_rand;
+ BOOST_FOREACH(const CAddress &addr, vAddr)
+ pfrom->PushAddress(addr, insecure_rand);
+ }
+
+
+ else if (strCommand == NetMsgType::MEMPOOL)
+ {
+ if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted)
+ {
+ 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)
+ {
+ LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
+ pfrom->fDisconnect = true;
+ return true;
+ }
+
+ LOCK(pfrom->cs_inventory);
+ pfrom->fSendMempool = true;
+ }
+
+
+ else if (strCommand == NetMsgType::PING)
+ {
+ if (pfrom->nVersion > BIP0031_VERSION)
+ {
+ uint64_t nonce = 0;
+ vRecv >> nonce;
+ // Echo the message back with the nonce. This allows for two useful features:
+ //
+ // 1) A remote node can quickly check if the connection is operational
+ // 2) Remote nodes can measure the latency of the network thread. If this node
+ // is overloaded it won't respond to pings quickly and the remote node can
+ // avoid sending us more work, like chain download requests.
+ //
+ // The nonce stops the remote getting confused between different pings: without
+ // 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));
+ }
+ }
+
+
+ else if (strCommand == NetMsgType::PONG)
+ {
+ int64_t pingUsecEnd = nTimeReceived;
+ uint64_t nonce = 0;
+ size_t nAvail = vRecv.in_avail();
+ bool bPingFinished = false;
+ std::string sProblem;
+
+ if (nAvail >= sizeof(nonce)) {
+ vRecv >> nonce;
+
+ // Only process pong message if there is an outstanding ping (old ping without nonce should never pong)
+ if (pfrom->nPingNonceSent != 0) {
+ if (nonce == pfrom->nPingNonceSent) {
+ // Matching pong received, this ping is no longer outstanding
+ bPingFinished = true;
+ int64_t pingUsecTime = pingUsecEnd - pfrom->nPingUsecStart;
+ if (pingUsecTime > 0) {
+ // Successful ping time measurement, replace previous
+ pfrom->nPingUsecTime = pingUsecTime;
+ pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime.load(), pingUsecTime);
+ } else {
+ // This should never happen
+ sProblem = "Timing mishap";
+ }
+ } else {
+ // Nonce mismatches are normal when pings are overlapping
+ sProblem = "Nonce mismatch";
+ if (nonce == 0) {
+ // This is most likely a bug in another implementation somewhere; cancel this ping
+ bPingFinished = true;
+ sProblem = "Nonce zero";
+ }
+ }
+ } else {
+ sProblem = "Unsolicited pong without ping";
+ }
+ } else {
+ // This is most likely a bug in another implementation somewhere; cancel this ping
+ bPingFinished = true;
+ sProblem = "Short payload";
+ }
+
+ if (!(sProblem.empty())) {
+ LogPrint(BCLog::NET, "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
+ pfrom->GetId(),
+ sProblem,
+ pfrom->nPingNonceSent,
+ nonce,
+ nAvail);
+ }
+ if (bPingFinished) {
+ pfrom->nPingNonceSent = 0;
+ }
+ }
+
+
+ else if (strCommand == NetMsgType::FILTERLOAD)
+ {
+ CBloomFilter filter;
+ vRecv >> filter;
+
+ if (!filter.IsWithinSizeConstraints())
+ {
+ // There is no excuse for sending a too-large filter
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 100);
+ }
+ else
+ {
+ LOCK(pfrom->cs_filter);
+ delete pfrom->pfilter;
+ pfrom->pfilter = new CBloomFilter(filter);
+ pfrom->pfilter->UpdateEmptyFull();
+ pfrom->fRelayTxes = true;
+ }
+ }
+
+
+ else if (strCommand == NetMsgType::FILTERADD)
+ {
+ std::vector<unsigned char> vData;
+ vRecv >> vData;
+
+ // Nodes must NEVER send a data item > 520 bytes (the max size for a script data object,
+ // and thus, the maximum size any matched object can have) in a filteradd message
+ bool bad = false;
+ if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) {
+ bad = true;
+ } else {
+ LOCK(pfrom->cs_filter);
+ if (pfrom->pfilter) {
+ pfrom->pfilter->insert(vData);
+ } else {
+ bad = true;
+ }
+ }
+ if (bad) {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 100);
+ }
+ }
+
+
+ else if (strCommand == NetMsgType::FILTERCLEAR)
+ {
+ LOCK(pfrom->cs_filter);
+ if (pfrom->GetLocalServices() & NODE_BLOOM) {
+ delete pfrom->pfilter;
+ pfrom->pfilter = new CBloomFilter();
+ }
+ pfrom->fRelayTxes = true;
+ }
+
+ else if (strCommand == NetMsgType::FEEFILTER) {
+ CAmount newFeeFilter = 0;
+ vRecv >> newFeeFilter;
+ if (MoneyRange(newFeeFilter)) {
+ {
+ LOCK(pfrom->cs_feeFilter);
+ pfrom->minFeeFilter = newFeeFilter;
+ }
+ LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->GetId());
+ }
+ }
+
+ else if (strCommand == NetMsgType::NOTFOUND) {
+ // We do not care about the NOTFOUND message, but logging an Unknown Command
+ // message would be undesirable as we transmit it ourselves.
+ }
+
+ else {
+ // Ignore unknown commands for extensibility
+ LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId());
+ }
+
+
+
+ return true;
+}
+
+static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman)
+{
+ AssertLockHeld(cs_main);
+ CNodeState &state = *State(pnode->GetId());
+
+ BOOST_FOREACH(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 ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& interruptMsgProc)
+{
+ const CChainParams& chainparams = Params();
+ //
+ // Message format
+ // (4) message start
+ // (12) command
+ // (4) size
+ // (4) checksum
+ // (x) data
+ //
+ bool fMoreWork = false;
+
+ if (!pfrom->vRecvGetData.empty())
+ ProcessGetData(pfrom, chainparams.GetConsensus(), connman, interruptMsgProc);
+
+ if (pfrom->fDisconnect)
+ return false;
+
+ // 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;
+
+ 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->GetId());
+ return fMoreWork;
+ }
+ std::string strCommand = hdr.GetCommand();
+
+ // 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)
+ {
+ 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"))
+ {
+ // 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()");
+ }
+ }
+ catch (const std::exception& e) {
+ PrintExceptionContinue(&e, "ProcessMessages()");
+ } catch (...) {
+ PrintExceptionContinue(NULL, "ProcessMessages()");
+ }
+
+ if (!fRet) {
+ LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->GetId());
+ }
+
+ LOCK(cs_main);
+ SendRejectsAndCheckIfBanned(pfrom, connman);
+
+ return fMoreWork;
+}
+
+class CompareInvMempoolOrder
+{
+ CTxMemPool *mp;
+public:
+ CompareInvMempoolOrder(CTxMemPool *_mempool)
+ {
+ mp = _mempool;
+ }
+
+ bool operator()(std::set<uint256>::iterator a, std::set<uint256>::iterator b)
+ {
+ /* As std::make_heap produces a max-heap, we want the entries with the
+ * fewest ancestors/highest fee to sort later. */
+ return mp->CompareDepthAndScore(*b, *a);
+ }
+};
+
+bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interruptMsgProc)
+{
+ const Consensus::Params& consensusParams = Params().GetConsensus();
+ {
+ // 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.
+ const CNetMsgMaker msgMaker(pto->GetSendVersion());
+
+ //
+ // Message: ping
+ //
+ bool pingSend = false;
+ if (pto->fPingQueued) {
+ // RPC ping request by user
+ pingSend = true;
+ }
+ if (pto->nPingNonceSent == 0 && pto->nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros()) {
+ // Ping automatically sent as a latency probe & keepalive.
+ pingSend = true;
+ }
+ if (pingSend) {
+ uint64_t nonce = 0;
+ while (nonce == 0) {
+ GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
+ }
+ pto->fPingQueued = false;
+ pto->nPingUsecStart = GetTimeMicros();
+ if (pto->nVersion > BIP0031_VERSION) {
+ pto->nPingNonceSent = 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));
+ }
+ }
+
+ TRY_LOCK(cs_main, lockMain); // Acquire cs_main for IsInitialBlockDownload() and CNodeState()
+ if (!lockMain)
+ return true;
+
+ if (SendRejectsAndCheckIfBanned(pto, connman))
+ return true;
+ CNodeState &state = *State(pto->GetId());
+
+ // Address refresh broadcast
+ int64_t nNow = GetTimeMicros();
+ if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
+ AdvertiseLocal(pto);
+ pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
+ }
+
+ //
+ // Message: addr
+ //
+ if (pto->nNextAddrSend < nNow) {
+ pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL);
+ std::vector<CAddress> vAddr;
+ vAddr.reserve(pto->vAddrToSend.size());
+ BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend)
+ {
+ if (!pto->addrKnown.contains(addr.GetKey()))
+ {
+ pto->addrKnown.insert(addr.GetKey());
+ vAddr.push_back(addr);
+ // receiver rejects addr messages larger than 1000
+ if (vAddr.size() >= 1000)
+ {
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
+ vAddr.clear();
+ }
+ }
+ }
+ pto->vAddrToSend.clear();
+ if (!vAddr.empty())
+ 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)
+ 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;
+ nSyncStarted++;
+ const CBlockIndex *pindexStart = pindexBestHeader;
+ /* If possible, start at the block preceding the currently
+ best known header. This ensures that we always get a
+ non-empty list of headers back as long as the peer
+ is up-to-date. With a non-empty response, we can initialise
+ the peer's known best block. This wouldn't be possible
+ if we requested starting at pindexBestHeader and
+ got back an empty response. */
+ if (pindexStart->pprev)
+ pindexStart = pindexStart->pprev;
+ 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()));
+ }
+ }
+
+ // Resend wallet transactions that haven't gotten in a block yet
+ // Except during reindex, importing and IBD, when old wallet
+ // transactions become unconfirmed and spams other nodes.
+ if (!fReindex && !fImporting && !IsInitialBlockDownload())
+ {
+ GetMainSignals().Broadcast(nTimeBestReceived, &connman);
+ }
+
+ //
+ // Try sending block announcements via headers
+ //
+ {
+ // If we have less than MAX_BLOCKS_TO_ANNOUNCE in our
+ // list of block hashes we're relaying, and our peer wants
+ // headers announcements, then find the first header
+ // not yet known to our peer but would connect, and send.
+ // If no header would connect, or if we have too many
+ // blocks, or if the peer doesn't want headers, just
+ // add all to the inv queue.
+ LOCK(pto->cs_inventory);
+ 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->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) {
+ BlockMap::iterator mi = mapBlockIndex.find(hash);
+ assert(mi != mapBlockIndex.end());
+ const CBlockIndex *pindex = mi->second;
+ if (chainActive[pindex->nHeight] != pindex) {
+ // Bail out if we reorged away from this block
+ fRevertToInv = true;
+ break;
+ }
+ if (pBestIndex != NULL && 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
+ // regular operation (because reorgs should take us to
+ // a chain that has some block not on the prior chain,
+ // which should be caught by the prior check), but one
+ // way this could happen is by using invalidateblock /
+ // reconsiderblock repeatedly on the tip, causing it to
+ // be added multiple times to vBlockHashesToAnnounce.
+ // Robustly deal with this rare situation by reverting
+ // to an inv.
+ fRevertToInv = true;
+ break;
+ }
+ pBestIndex = pindex;
+ if (fFoundStartingHeader) {
+ // add this to the headers message
+ 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)) {
+ // Peer doesn't have this header but they do have the prior one.
+ // Start sending headers.
+ fFoundStartingHeader = true;
+ vHeaders.push_back(pindex->GetBlockHeader());
+ } else {
+ // Peer doesn't have this header or the prior one -- nothing will
+ // connect, so bail out.
+ fRevertToInv = true;
+ break;
+ }
+ }
+ }
+ if (!fRevertToInv && !vHeaders.empty()) {
+ 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(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;
+
+ bool fGotBlockFromCache = false;
+ {
+ LOCK(cs_most_recent_block);
+ if (most_recent_block_hash == pBestIndex->GetBlockHash()) {
+ 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));
+ }
+ fGotBlockFromCache = true;
+ }
+ }
+ if (!fGotBlockFromCache) {
+ CBlock block;
+ bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams);
+ assert(ret);
+ CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);
+ connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
+ }
+ state.pindexBestHeaderSent = pBestIndex;
+ } else if (state.fPreferHeaders) {
+ if (vHeaders.size() > 1) {
+ 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->GetId());
+ } else {
+ 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));
+ state.pindexBestHeaderSent = pBestIndex;
+ } else
+ fRevertToInv = true;
+ }
+ if (fRevertToInv) {
+ // If falling back to using an inv, just try to inv the tip.
+ // The last entry in vBlockHashesToAnnounce was our tip at some point
+ // in the past.
+ if (!pto->vBlockHashesToAnnounce.empty()) {
+ const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back();
+ BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce);
+ assert(mi != mapBlockIndex.end());
+ const CBlockIndex *pindex = mi->second;
+
+ // Warn if we're announcing a block that is not on the main chain.
+ // This should be very rare and could be optimized out.
+ // Just log for now.
+ if (chainActive[pindex->nHeight] != pindex) {
+ 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(BCLog::NET, "%s: sending inv peer=%d hash=%s\n", __func__,
+ pto->GetId(), hashToAnnounce.ToString());
+ }
+ }
+ }
+ pto->vBlockHashesToAnnounce.clear();
+ }
+
+ //
+ // Message: inventory
+ //
+ 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) {
+ vInv.push_back(CInv(MSG_BLOCK, hash));
+ if (vInv.size() == MAX_INV_SZ) {
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ vInv.clear();
+ }
+ }
+ pto->vInventoryBlockToSend.clear();
+
+ // Check whether periodic sends should happen
+ bool fSendTrickle = pto->fWhitelisted;
+ if (pto->nNextInvSend < nNow) {
+ fSendTrickle = true;
+ // Use half the delay for outbound peers, as there is less privacy concern for them.
+ pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound);
+ }
+
+ // Time to send but the peer has requested we not relay transactions.
+ if (fSendTrickle) {
+ LOCK(pto->cs_filter);
+ if (!pto->fRelayTxes) pto->setInventoryTxToSend.clear();
+ }
+
+ // Respond to BIP35 mempool requests
+ if (fSendTrickle && pto->fSendMempool) {
+ auto vtxinfo = mempool.infoAll();
+ pto->fSendMempool = false;
+ CAmount filterrate = 0;
+ {
+ LOCK(pto->cs_feeFilter);
+ filterrate = pto->minFeeFilter;
+ }
+
+ LOCK(pto->cs_filter);
+
+ for (const auto& txinfo : vtxinfo) {
+ const uint256& hash = txinfo.tx->GetHash();
+ CInv inv(MSG_TX, hash);
+ pto->setInventoryTxToSend.erase(hash);
+ if (filterrate) {
+ if (txinfo.feeRate.GetFeePerK() < filterrate)
+ continue;
+ }
+ if (pto->pfilter) {
+ if (!pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
+ }
+ pto->filterInventoryKnown.insert(hash);
+ vInv.push_back(inv);
+ if (vInv.size() == MAX_INV_SZ) {
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ vInv.clear();
+ }
+ }
+ pto->timeLastMempoolReq = GetTime();
+ }
+
+ // Determine transactions to relay
+ if (fSendTrickle) {
+ // Produce a vector with all candidates for sending
+ 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);
+ }
+ CAmount filterrate = 0;
+ {
+ LOCK(pto->cs_feeFilter);
+ filterrate = pto->minFeeFilter;
+ }
+ // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
+ // A heap is used so that not all items need sorting if only a few are being sent.
+ CompareInvMempoolOrder compareInvMempoolOrder(&mempool);
+ std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
+ // No reason to drain out at many times the network's capacity,
+ // especially since we have many peers and some will draw much shorter delays.
+ unsigned int nRelayedTransactions = 0;
+ LOCK(pto->cs_filter);
+ while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
+ // Fetch the top element from the heap
+ std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
+ std::set<uint256>::iterator it = vInvTx.back();
+ vInvTx.pop_back();
+ uint256 hash = *it;
+ // Remove it from the to-be-sent set
+ pto->setInventoryTxToSend.erase(it);
+ // Check if not in the filter already
+ if (pto->filterInventoryKnown.contains(hash)) {
+ continue;
+ }
+ // Not in the mempool anymore? don't bother sending it.
+ auto txinfo = mempool.info(hash);
+ if (!txinfo.tx) {
+ continue;
+ }
+ if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) {
+ continue;
+ }
+ if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
+ // Send
+ vInv.push_back(CInv(MSG_TX, hash));
+ nRelayedTransactions++;
+ {
+ // Expire old relay messages
+ while (!vRelayExpiration.empty() && vRelayExpiration.front().first < nNow)
+ {
+ mapRelay.erase(vRelayExpiration.front().second);
+ vRelayExpiration.pop_front();
+ }
+
+ auto ret = mapRelay.insert(std::make_pair(hash, std::move(txinfo.tx)));
+ if (ret.second) {
+ vRelayExpiration.push_back(std::make_pair(nNow + 15 * 60 * 1000000, ret.first));
+ }
+ }
+ if (vInv.size() == MAX_INV_SZ) {
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ vInv.clear();
+ }
+ pto->filterInventoryKnown.insert(hash);
+ }
+ }
+ }
+ if (!vInv.empty())
+ connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+
+ // Detect whether we're stalling
+ nNow = GetTimeMicros();
+ if (state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) {
+ // 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->GetId());
+ pto->fDisconnect = true;
+ return true;
+ }
+ // In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval
+ // (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout.
+ // We compensate for other peers to prevent killing off peers due to our own downstream link
+ // being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes
+ // to unreasonably increase our timeout.
+ if (state.vBlocksInFlight.size() > 0) {
+ 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->GetId());
+ pto->fDisconnect = true;
+ return true;
+ }
+ }
+
+ //
+ // Message: getdata (blocks)
+ //
+ std::vector<CInv> vGetData;
+ if (!pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ 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);
+ vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
+ MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, 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(BCLog::NET, "Stall started peer=%d\n", staller);
+ }
+ }
+ }
+
+ //
+ // Message: getdata (non-blocks)
+ //
+ while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
+ {
+ const CInv& inv = (*pto->mapAskFor.begin()).second;
+ if (!AlreadyHave(inv))
+ {
+ 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));
+ vGetData.clear();
+ }
+ } else {
+ //If we're not going to ask, don't expect a response.
+ pto->setAskFor.erase(inv.hash);
+ }
+ pto->mapAskFor.erase(pto->mapAskFor.begin());
+ }
+ if (!vGetData.empty())
+ 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();
+ 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);
+ // 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));
+ pto->lastSentFeeFilter = filterToSend;
+ }
+ pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
+ }
+ // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
+ // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
+ else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter &&
+ (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) {
+ pto->nextSendTimeFeeFilter = timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
+ }
+ }
+ }
+ return true;
+}
+
+class CNetProcessingCleanup
+{
+public:
+ CNetProcessingCleanup() {}
+ ~CNetProcessingCleanup() {
+ // orphan transactions
+ mapOrphanTransactions.clear();
+ mapOrphanTransactionsByPrev.clear();
+ }
+} instance_of_cnetprocessingcleanup;
diff --git a/src/net_processing.h b/src/net_processing.h
new file mode 100644
index 0000000000..f460595bc1
--- /dev/null
+++ b/src/net_processing.h
@@ -0,0 +1,63 @@
+// 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_NET_PROCESSING_H
+#define BITCOIN_NET_PROCESSING_H
+
+#include "net.h"
+#include "validationinterface.h"
+
+/** 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;
+
+/** Register with a network node to receive its signals */
+void RegisterNodeSignals(CNodeSignals& nodeSignals);
+/** Unregister a network node */
+void UnregisterNodeSignals(CNodeSignals& nodeSignals);
+
+class PeerLogicValidation : public CValidationInterface {
+private:
+ CConnman* connman;
+
+public:
+ PeerLogicValidation(CConnman* connmanIn);
+
+ 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;
+};
+
+struct CNodeStateStats {
+ int nMisbehavior;
+ int nSyncHeight;
+ int nCommonHeight;
+ std::vector<int> vHeightInFlight;
+};
+
+/** Get statistics from node state */
+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, const 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, const std::atomic<bool>& interrupt);
+
+#endif // BITCOIN_NET_PROCESSING_H
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
new file mode 100644
index 0000000000..34a7029862
--- /dev/null
+++ b/src/netaddress.cpp
@@ -0,0 +1,710 @@
+// 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.
+
+#ifdef HAVE_CONFIG_H
+#include "config/bitcoin-config.h"
+#endif
+
+#include "netaddress.h"
+#include "hash.h"
+#include "utilstrencodings.h"
+#include "tinyformat.h"
+
+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};
+
+void CNetAddr::Init()
+{
+ memset(ip, 0, sizeof(ip));
+ scopeId = 0;
+}
+
+void CNetAddr::SetIP(const CNetAddr& ipIn)
+{
+ memcpy(ip, ipIn.ip, sizeof(ip));
+}
+
+void CNetAddr::SetRaw(Network network, const uint8_t *ip_in)
+{
+ switch(network)
+ {
+ case NET_IPV4:
+ memcpy(ip, pchIPv4, 12);
+ memcpy(ip+12, ip_in, 4);
+ break;
+ case NET_IPV6:
+ memcpy(ip, ip_in, 16);
+ break;
+ default:
+ assert(!"invalid network");
+ }
+}
+
+bool CNetAddr::SetSpecial(const std::string &strName)
+{
+ if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
+ std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str());
+ if (vchAddr.size() != 16-sizeof(pchOnionCat))
+ return false;
+ memcpy(ip, pchOnionCat, sizeof(pchOnionCat));
+ for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++)
+ ip[i + sizeof(pchOnionCat)] = vchAddr[i];
+ return true;
+ }
+ return false;
+}
+
+CNetAddr::CNetAddr()
+{
+ Init();
+}
+
+CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
+{
+ SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr);
+}
+
+CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope)
+{
+ SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr);
+ scopeId = scope;
+}
+
+unsigned int CNetAddr::GetByte(int n) const
+{
+ return ip[15-n];
+}
+
+bool CNetAddr::IsIPv4() const
+{
+ return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0);
+}
+
+bool CNetAddr::IsIPv6() const
+{
+ return (!IsIPv4() && !IsTor());
+}
+
+bool CNetAddr::IsRFC1918() const
+{
+ return IsIPv4() && (
+ GetByte(3) == 10 ||
+ (GetByte(3) == 192 && GetByte(2) == 168) ||
+ (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31)));
+}
+
+bool CNetAddr::IsRFC2544() const
+{
+ return IsIPv4() && GetByte(3) == 198 && (GetByte(2) == 18 || GetByte(2) == 19);
+}
+
+bool CNetAddr::IsRFC3927() const
+{
+ return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
+}
+
+bool CNetAddr::IsRFC6598() const
+{
+ return IsIPv4() && GetByte(3) == 100 && GetByte(2) >= 64 && GetByte(2) <= 127;
+}
+
+bool CNetAddr::IsRFC5737() const
+{
+ return IsIPv4() && ((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) ||
+ (GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) ||
+ (GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113));
+}
+
+bool CNetAddr::IsRFC3849() const
+{
+ return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8;
+}
+
+bool CNetAddr::IsRFC3964() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x02);
+}
+
+bool CNetAddr::IsRFC6052() const
+{
+ static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0};
+ return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0);
+}
+
+bool CNetAddr::IsRFC4380() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0);
+}
+
+bool CNetAddr::IsRFC4862() const
+{
+ static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0};
+ return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0);
+}
+
+bool CNetAddr::IsRFC4193() const
+{
+ return ((GetByte(15) & 0xFE) == 0xFC);
+}
+
+bool CNetAddr::IsRFC6145() const
+{
+ static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0};
+ return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0);
+}
+
+bool CNetAddr::IsRFC4843() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
+}
+
+bool CNetAddr::IsTor() const
+{
+ return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
+}
+
+bool CNetAddr::IsLocal() const
+{
+ // IPv4 loopback
+ if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0))
+ return true;
+
+ // IPv6 loopback (::1/128)
+ static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+ if (memcmp(ip, pchLocal, 16) == 0)
+ return true;
+
+ return false;
+}
+
+bool CNetAddr::IsValid() const
+{
+ // Cleanup 3-byte shifted addresses caused by garbage in size field
+ // of addr messages from versions before 0.2.9 checksum.
+ // Two consecutive addr messages look like this:
+ // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
+ // so if the first length field is garbled, it reads the second batch
+ // of addr misaligned by 3 bytes.
+ if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
+ return false;
+
+ // unspecified IPv6 address (::/128)
+ unsigned char ipNone6[16] = {};
+ if (memcmp(ip, ipNone6, 16) == 0)
+ return false;
+
+ // documentation IPv6 address
+ if (IsRFC3849())
+ return false;
+
+ if (IsIPv4())
+ {
+ // INADDR_NONE
+ uint32_t ipNone = INADDR_NONE;
+ if (memcmp(ip+12, &ipNone, 4) == 0)
+ return false;
+
+ // 0
+ ipNone = 0;
+ if (memcmp(ip+12, &ipNone, 4) == 0)
+ return false;
+ }
+
+ return true;
+}
+
+bool CNetAddr::IsRoutable() const
+{
+ return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal());
+}
+
+enum Network CNetAddr::GetNetwork() const
+{
+ if (!IsRoutable())
+ return NET_UNROUTABLE;
+
+ if (IsIPv4())
+ return NET_IPV4;
+
+ if (IsTor())
+ return NET_TOR;
+
+ return NET_IPV6;
+}
+
+std::string CNetAddr::ToStringIP() const
+{
+ if (IsTor())
+ return EncodeBase32(&ip[6], 10) + ".onion";
+ 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))
+ return std::string(name);
+ }
+ if (IsIPv4())
+ return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
+ else
+ return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
+ GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12),
+ GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8),
+ GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4),
+ GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0));
+}
+
+std::string CNetAddr::ToString() const
+{
+ return ToStringIP();
+}
+
+bool operator==(const CNetAddr& a, const CNetAddr& b)
+{
+ return (memcmp(a.ip, b.ip, 16) == 0);
+}
+
+bool operator!=(const CNetAddr& a, const CNetAddr& b)
+{
+ return (memcmp(a.ip, b.ip, 16) != 0);
+}
+
+bool operator<(const CNetAddr& a, const CNetAddr& b)
+{
+ return (memcmp(a.ip, b.ip, 16) < 0);
+}
+
+bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
+{
+ if (!IsIPv4())
+ return false;
+ memcpy(pipv4Addr, ip+12, 4);
+ return true;
+}
+
+bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
+{
+ memcpy(pipv6Addr, ip, 16);
+ return true;
+}
+
+// get canonical identifier of an address' group
+// no two connections will be attempted to addresses with the same group
+std::vector<unsigned char> CNetAddr::GetGroup() const
+{
+ std::vector<unsigned char> vchRet;
+ int nClass = NET_IPV6;
+ int nStartByte = 0;
+ int nBits = 16;
+
+ // all local addresses belong to the same group
+ if (IsLocal())
+ {
+ nClass = 255;
+ nBits = 0;
+ }
+
+ // all unroutable addresses belong to the same group
+ if (!IsRoutable())
+ {
+ nClass = NET_UNROUTABLE;
+ nBits = 0;
+ }
+ // for IPv4 addresses, '1' + the 16 higher-order bits of the IP
+ // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
+ else if (IsIPv4() || IsRFC6145() || IsRFC6052())
+ {
+ nClass = NET_IPV4;
+ nStartByte = 12;
+ }
+ // for 6to4 tunnelled addresses, use the encapsulated IPv4 address
+ else if (IsRFC3964())
+ {
+ nClass = NET_IPV4;
+ nStartByte = 2;
+ }
+ // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
+ else if (IsRFC4380())
+ {
+ vchRet.push_back(NET_IPV4);
+ vchRet.push_back(GetByte(3) ^ 0xFF);
+ vchRet.push_back(GetByte(2) ^ 0xFF);
+ return vchRet;
+ }
+ else if (IsTor())
+ {
+ nClass = NET_TOR;
+ nStartByte = 6;
+ nBits = 4;
+ }
+ // for he.net, use /36 groups
+ else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
+ nBits = 36;
+ // for the rest of the IPv6 network, use /32 groups
+ else
+ nBits = 32;
+
+ vchRet.push_back(nClass);
+ while (nBits >= 8)
+ {
+ vchRet.push_back(GetByte(15 - nStartByte));
+ nStartByte++;
+ nBits -= 8;
+ }
+ if (nBits > 0)
+ vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1));
+
+ return vchRet;
+}
+
+uint64_t CNetAddr::GetHash() const
+{
+ uint256 hash = Hash(&ip[0], &ip[16]);
+ uint64_t nRet;
+ memcpy(&nRet, &hash, sizeof(nRet));
+ return nRet;
+}
+
+// private extensions to enum Network, only returned by GetExtNetwork,
+// and only used in GetReachabilityFrom
+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)
+ return NET_UNKNOWN;
+ if (addr->IsRFC4380())
+ return NET_TEREDO;
+ return addr->GetNetwork();
+}
+
+/** Calculates a metric for how reachable (*this) is from a given partner */
+int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
+{
+ enum Reachability {
+ REACH_UNREACHABLE,
+ REACH_DEFAULT,
+ REACH_TEREDO,
+ REACH_IPV6_WEAK,
+ REACH_IPV4,
+ REACH_IPV6_STRONG,
+ REACH_PRIVATE
+ };
+
+ if (!IsRoutable())
+ return REACH_UNREACHABLE;
+
+ int ourNet = GetExtNetwork(this);
+ int theirNet = GetExtNetwork(paddrPartner);
+ bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145();
+
+ switch(theirNet) {
+ case NET_IPV4:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_IPV4: return REACH_IPV4;
+ }
+ case NET_IPV6:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_TEREDO: return REACH_TEREDO;
+ case NET_IPV4: return REACH_IPV4;
+ case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled
+ }
+ case NET_TOR:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well
+ case NET_TOR: return REACH_PRIVATE;
+ }
+ case NET_TEREDO:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_TEREDO: return REACH_TEREDO;
+ case NET_IPV6: return REACH_IPV6_WEAK;
+ case NET_IPV4: return REACH_IPV4;
+ }
+ case NET_UNKNOWN:
+ case NET_UNROUTABLE:
+ default:
+ switch(ourNet) {
+ default: return REACH_DEFAULT;
+ case NET_TEREDO: return REACH_TEREDO;
+ case NET_IPV6: return REACH_IPV6_WEAK;
+ case NET_IPV4: return REACH_IPV4;
+ case NET_TOR: return REACH_PRIVATE; // either from Tor, or don't care about our address
+ }
+ }
+}
+
+void CService::Init()
+{
+ port = 0;
+}
+
+CService::CService()
+{
+ Init();
+}
+
+CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn)
+{
+}
+
+CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn)
+{
+}
+
+CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn)
+{
+}
+
+CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port))
+{
+ assert(addr.sin_family == AF_INET);
+}
+
+CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr, addr.sin6_scope_id), port(ntohs(addr.sin6_port))
+{
+ assert(addr.sin6_family == AF_INET6);
+}
+
+bool CService::SetSockAddr(const struct sockaddr *paddr)
+{
+ switch (paddr->sa_family) {
+ case AF_INET:
+ *this = CService(*(const struct sockaddr_in*)paddr);
+ return true;
+ case AF_INET6:
+ *this = CService(*(const struct sockaddr_in6*)paddr);
+ return true;
+ default:
+ return false;
+ }
+}
+
+unsigned short CService::GetPort() const
+{
+ return port;
+}
+
+bool operator==(const CService& a, const CService& b)
+{
+ return (CNetAddr)a == (CNetAddr)b && a.port == b.port;
+}
+
+bool operator!=(const CService& a, const CService& b)
+{
+ return (CNetAddr)a != (CNetAddr)b || a.port != b.port;
+}
+
+bool operator<(const CService& a, const CService& b)
+{
+ return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port);
+}
+
+bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
+{
+ if (IsIPv4()) {
+ if (*addrlen < (socklen_t)sizeof(struct sockaddr_in))
+ return false;
+ *addrlen = sizeof(struct sockaddr_in);
+ struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr;
+ memset(paddrin, 0, *addrlen);
+ if (!GetInAddr(&paddrin->sin_addr))
+ return false;
+ paddrin->sin_family = AF_INET;
+ paddrin->sin_port = htons(port);
+ return true;
+ }
+ if (IsIPv6()) {
+ if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6))
+ return false;
+ *addrlen = sizeof(struct sockaddr_in6);
+ struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr;
+ memset(paddrin6, 0, *addrlen);
+ if (!GetIn6Addr(&paddrin6->sin6_addr))
+ return false;
+ paddrin6->sin6_scope_id = scopeId;
+ paddrin6->sin6_family = AF_INET6;
+ paddrin6->sin6_port = htons(port);
+ return true;
+ }
+ return false;
+}
+
+std::vector<unsigned char> CService::GetKey() const
+{
+ std::vector<unsigned char> vKey;
+ vKey.resize(18);
+ memcpy(&vKey[0], ip, 16);
+ vKey[16] = port / 0x100;
+ vKey[17] = port & 0x0FF;
+ return vKey;
+}
+
+std::string CService::ToStringPort() const
+{
+ return strprintf("%u", port);
+}
+
+std::string CService::ToStringIPPort() const
+{
+ if (IsIPv4() || IsTor()) {
+ return ToStringIP() + ":" + ToStringPort();
+ } else {
+ return "[" + ToStringIP() + "]:" + ToStringPort();
+ }
+}
+
+std::string CService::ToString() const
+{
+ return ToStringIPPort();
+}
+
+void CService::SetPort(unsigned short portIn)
+{
+ port = portIn;
+}
+
+CSubNet::CSubNet():
+ valid(false)
+{
+ memset(netmask, 0, sizeof(netmask));
+}
+
+CSubNet::CSubNet(const CNetAddr &addr, int32_t mask)
+{
+ valid = true;
+ network = addr;
+ // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address
+ memset(netmask, 255, sizeof(netmask));
+
+ // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n
+ const int astartofs = network.IsIPv4() ? 12 : 0;
+
+ int32_t n = mask;
+ if(n >= 0 && n <= (128 - astartofs*8)) // Only valid if in range of bits of address
+ {
+ n += astartofs*8;
+ // Clear bits [n..127]
+ for (; n < 128; ++n)
+ netmask[n>>3] &= ~(1<<(7-(n&7)));
+ } else
+ valid = false;
+
+ // Normalize network according to netmask
+ for(int x=0; x<16; ++x)
+ network.ip[x] &= netmask[x];
+}
+
+CSubNet::CSubNet(const CNetAddr &addr, const CNetAddr &mask)
+{
+ valid = true;
+ network = addr;
+ // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address
+ memset(netmask, 255, sizeof(netmask));
+
+ // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n
+ const int astartofs = network.IsIPv4() ? 12 : 0;
+
+ for(int x=astartofs; x<16; ++x)
+ netmask[x] = mask.ip[x];
+
+ // Normalize network according to netmask
+ for(int x=0; x<16; ++x)
+ network.ip[x] &= netmask[x];
+}
+
+CSubNet::CSubNet(const CNetAddr &addr):
+ valid(addr.IsValid())
+{
+ memset(netmask, 255, sizeof(netmask));
+ network = addr;
+}
+
+bool CSubNet::Match(const CNetAddr &addr) const
+{
+ if (!valid || !addr.IsValid())
+ return false;
+ for(int x=0; x<16; ++x)
+ if ((addr.ip[x] & netmask[x]) != network.ip[x])
+ return false;
+ return true;
+}
+
+static inline int NetmaskBits(uint8_t x)
+{
+ switch(x) {
+ case 0x00: return 0; break;
+ case 0x80: return 1; break;
+ case 0xc0: return 2; break;
+ case 0xe0: return 3; break;
+ case 0xf0: return 4; break;
+ case 0xf8: return 5; break;
+ case 0xfc: return 6; break;
+ case 0xfe: return 7; break;
+ case 0xff: return 8; break;
+ default: return -1; break;
+ }
+}
+
+std::string CSubNet::ToString() const
+{
+ /* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */
+ int cidr = 0;
+ bool valid_cidr = true;
+ int n = network.IsIPv4() ? 12 : 0;
+ for (; n < 16 && netmask[n] == 0xff; ++n)
+ cidr += 8;
+ if (n < 16) {
+ int bits = NetmaskBits(netmask[n]);
+ if (bits < 0)
+ valid_cidr = false;
+ else
+ cidr += bits;
+ ++n;
+ }
+ for (; n < 16 && valid_cidr; ++n)
+ if (netmask[n] != 0x00)
+ valid_cidr = false;
+
+ /* Format output */
+ std::string strNetmask;
+ if (valid_cidr) {
+ strNetmask = strprintf("%u", cidr);
+ } else {
+ if (network.IsIPv4())
+ strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]);
+ else
+ strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
+ netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3],
+ netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7],
+ netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11],
+ netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]);
+ }
+
+ return network.ToString() + "/" + strNetmask;
+}
+
+bool CSubNet::IsValid() const
+{
+ return valid;
+}
+
+bool operator==(const CSubNet& a, const CSubNet& b)
+{
+ return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16);
+}
+
+bool operator!=(const CSubNet& a, const CSubNet& b)
+{
+ return !(a==b);
+}
+
+bool operator<(const CSubNet& a, const CSubNet& b)
+{
+ return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
+}
diff --git a/src/netaddress.h b/src/netaddress.h
new file mode 100644
index 0000000000..fbc4d1a65f
--- /dev/null
+++ b/src/netaddress.h
@@ -0,0 +1,170 @@
+// 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_NETADDRESS_H
+#define BITCOIN_NETADDRESS_H
+
+#if defined(HAVE_CONFIG_H)
+#include "config/bitcoin-config.h"
+#endif
+
+#include "compat.h"
+#include "serialize.h"
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+enum Network
+{
+ NET_UNROUTABLE = 0,
+ NET_IPV4,
+ NET_IPV6,
+ NET_TOR,
+
+ NET_MAX,
+};
+
+/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */
+class CNetAddr
+{
+ protected:
+ unsigned char ip[16]; // in network byte order
+ uint32_t scopeId; // for scoped/link-local ipv6 addresses
+
+ public:
+ CNetAddr();
+ CNetAddr(const struct in_addr& ipv4Addr);
+ void Init();
+ void SetIP(const CNetAddr& ip);
+
+ /**
+ * Set raw IPv4 or IPv6 address (in network byte order)
+ * @note Only NET_IPV4 and NET_IPV6 are allowed for network.
+ */
+ void SetRaw(Network network, const uint8_t *data);
+
+ 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 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)
+ bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
+ bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16)
+ bool IsRFC4193() const; // IPv6 unique local (FC00::/7)
+ bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32)
+ bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28)
+ bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
+ bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
+ bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
+ bool IsTor() const;
+ bool IsLocal() const;
+ bool IsRoutable() const;
+ bool IsValid() const;
+ enum Network GetNetwork() const;
+ std::string ToString() const;
+ std::string ToStringIP() const;
+ unsigned int GetByte(int n) const;
+ uint64_t GetHash() const;
+ bool GetInAddr(struct in_addr* pipv4Addr) const;
+ std::vector<unsigned char> GetGroup() const;
+ int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;
+
+ 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);
+ friend bool operator!=(const CNetAddr& a, const CNetAddr& b);
+ friend bool operator<(const CNetAddr& a, const CNetAddr& b);
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(FLATDATA(ip));
+ }
+
+ friend class CSubNet;
+};
+
+class CSubNet
+{
+ protected:
+ /// Network (base) address
+ CNetAddr network;
+ /// Netmask, in network byte order
+ uint8_t netmask[16];
+ /// Is this value valid? (only used to signal parse errors)
+ bool valid;
+
+ public:
+ CSubNet();
+ CSubNet(const CNetAddr &addr, int32_t mask);
+ CSubNet(const CNetAddr &addr, const CNetAddr &mask);
+
+ //constructor for single ip subnet (<ipv4>/32 or <ipv6>/128)
+ explicit CSubNet(const CNetAddr &addr);
+
+ bool Match(const CNetAddr &addr) const;
+
+ std::string ToString() const;
+ bool IsValid() const;
+
+ friend bool operator==(const CSubNet& a, const CSubNet& b);
+ friend bool operator!=(const CSubNet& a, const CSubNet& b);
+ friend bool operator<(const CSubNet& a, const CSubNet& b);
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(network);
+ READWRITE(FLATDATA(netmask));
+ READWRITE(FLATDATA(valid));
+ }
+};
+
+/** A combination of a network address (CNetAddr) and a (TCP) port */
+class CService : public CNetAddr
+{
+ protected:
+ unsigned short port; // host order
+
+ public:
+ CService();
+ CService(const CNetAddr& ip, unsigned short port);
+ CService(const struct in_addr& ipv4Addr, unsigned short port);
+ 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);
+ friend bool operator==(const CService& a, const CService& b);
+ friend bool operator!=(const CService& a, const CService& b);
+ friend bool operator<(const CService& a, const CService& b);
+ std::vector<unsigned char> GetKey() const;
+ std::string ToString() const;
+ std::string ToStringPort() const;
+ std::string ToStringIPPort() const;
+
+ CService(const struct in6_addr& ipv6Addr, unsigned short port);
+ CService(const struct sockaddr_in6& addr);
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(FLATDATA(ip));
+ unsigned short portN = htons(port);
+ READWRITE(FLATDATA(portN));
+ if (ser_action.ForRead())
+ port = ntohs(portN);
+ }
+};
+
+#endif // BITCOIN_NETADDRESS_H
diff --git a/src/netbase.cpp b/src/netbase.cpp
index e2a516986c..bdc725359a 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -16,22 +16,16 @@
#include "util.h"
#include "utilstrencodings.h"
-#ifdef HAVE_GETADDRINFO_A
-#include <netdb.h>
-#endif
+#include <atomic>
#ifndef WIN32
-#if HAVE_INET_PTON
-#include <arpa/inet.h>
-#endif
#include <fcntl.h>
#endif
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
-#include <boost/thread.hpp>
-#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
+#if !defined(HAVE_MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
@@ -42,10 +36,9 @@ static CCriticalSection cs_proxyInfos;
int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
bool fNameLookup = DEFAULT_NAME_LOOKUP;
-static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
-
// Need ample time for negotiation for very slow proxies such as Tor (milliseconds)
static const int SOCKS5_RECV_TIMEOUT = 20 * 1000;
+static std::atomic<bool> interruptSocks5Recv(false);
enum Network ParseNetwork(std::string net) {
boost::to_lower(net);
@@ -96,30 +89,9 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
}
}
-#ifdef HAVE_GETADDRINFO_A
- struct in_addr ipv4_addr;
-#ifdef HAVE_INET_PTON
- if (inet_pton(AF_INET, pszName, &ipv4_addr) > 0) {
- vIP.push_back(CNetAddr(ipv4_addr));
- return true;
- }
-
- struct in6_addr ipv6_addr;
- if (inet_pton(AF_INET6, pszName, &ipv6_addr) > 0) {
- vIP.push_back(CNetAddr(ipv6_addr));
- return true;
- }
-#else
- ipv4_addr.s_addr = inet_addr(pszName);
- if (ipv4_addr.s_addr != INADDR_NONE) {
- vIP.push_back(CNetAddr(ipv4_addr));
- return true;
- }
-#endif
-#endif
-
struct addrinfo aiHint;
memset(&aiHint, 0, sizeof(struct addrinfo));
+
aiHint.ai_socktype = SOCK_STREAM;
aiHint.ai_protocol = IPPROTO_TCP;
aiHint.ai_family = AF_UNSPEC;
@@ -128,33 +100,8 @@ 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;
-#ifdef HAVE_GETADDRINFO_A
- struct gaicb gcb, *query = &gcb;
- memset(query, 0, sizeof(struct gaicb));
- gcb.ar_name = pszName;
- gcb.ar_request = &aiHint;
- int nErr = getaddrinfo_a(GAI_NOWAIT, &query, 1, NULL);
- if (nErr)
- return false;
-
- do {
- // Should set the timeout limit to a reasonable value to avoid
- // generating unnecessary checking call during the polling loop,
- // while it can still response to stop request quick enough.
- // 2 seconds looks fine in our situation.
- struct timespec ts = { 2, 0 };
- gai_suspend(&query, 1, &ts);
- boost::this_thread::interruption_point();
-
- nErr = gai_error(query);
- if (0 == nErr)
- aiRes = query->ar_result;
- } while (nErr == EAI_INPROGRESS);
-#else
int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes);
-#endif
if (nErr)
return false;
@@ -195,6 +142,16 @@ bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nM
return LookupIntern(strHost.c_str(), vIP, nMaxSolutions, fAllowLookup);
}
+bool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup)
+{
+ std::vector<CNetAddr> vIP;
+ LookupHost(pszName, vIP, 1, fAllowLookup);
+ if(vIP.empty())
+ return false;
+ addr = vIP.front();
+ return true;
+}
+
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
{
if (pszName[0] == 0)
@@ -223,9 +180,14 @@ bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLoo
return true;
}
-bool LookupNumeric(const char *pszName, CService& addr, int portDefault)
+CService LookupNumeric(const char *pszName, int portDefault)
{
- return Lookup(pszName, addr, portDefault, false);
+ CService addr;
+ // "1.2:345" will fail to resolve the ip, but will still set the port.
+ // If the ip fails to resolve, re-init the result.
+ if(!Lookup(pszName, addr, portDefault, false))
+ addr = CService();
+ return addr;
}
struct timeval MillisToTimeval(int64_t nTimeout)
@@ -236,10 +198,18 @@ struct timeval MillisToTimeval(int64_t nTimeout)
return timeout;
}
+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.
- * This function can be interrupted by boost thread interrupt.
+ * This function can be interrupted by calling InterruptSocks5()
*
* @param data Buffer to receive into
* @param len Length of data to receive
@@ -247,7 +217,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(char* data, size_t len, int timeout, SOCKET& hSocket)
{
int64_t curTime = GetTimeMillis();
int64_t endTime = curTime + timeout;
@@ -260,12 +230,12 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
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;
@@ -273,16 +243,17 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
FD_SET(hSocket, &fdset);
int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval);
if (nRet == SOCKET_ERROR) {
- return false;
+ return IntrRecvError::NetworkError;
}
} else {
- return false;
+ return IntrRecvError::NetworkError;
}
}
- boost::this_thread::interruption_point();
+ if (interruptSocks5Recv)
+ return IntrRecvError::Interrupted;
curTime = GetTimeMillis();
}
- return len == 0;
+ return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
}
struct ProxyCredentials
@@ -309,7 +280,8 @@ std::string Socks5ErrorString(int err)
/** 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");
@@ -325,13 +297,13 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vSocks5Init.push_back(0x01); // # METHODS
vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
}
- ssize_t ret = send(hSocket, (const char*)begin_ptr(vSocks5Init), vSocks5Init.size(), MSG_NOSIGNAL);
+ 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)) {
+ 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;
@@ -350,14 +322,14 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
vAuth.push_back(auth->password.size());
vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
- ret = send(hSocket, (const char*)begin_ptr(vAuth), vAuth.size(), MSG_NOSIGNAL);
+ ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vAuth.size()) {
CloseSocket(hSocket);
return error("Error sending authentication to proxy");
}
- LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
+ LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
char pchRetA[2];
- if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
+ if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket);
return error("Error reading proxy authentication response");
}
@@ -380,15 +352,22 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
vSocks5.push_back((port >> 8) & 0xFF);
vSocks5.push_back((port >> 0) & 0xFF);
- ret = send(hSocket, (const char*)begin_ptr(vSocks5), vSocks5.size(), MSG_NOSIGNAL);
+ ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5.size()) {
CloseSocket(hSocket);
return error("Error sending to proxy");
}
char pchRet2[4];
- if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) {
+ 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) {
CloseSocket(hSocket);
@@ -407,30 +386,30 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
char 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 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
+ case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
case 0x03:
{
- 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;
}
@@ -479,7 +458,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
int nRet = select(hSocket + 1, NULL, &fdset, NULL, &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;
}
@@ -583,8 +562,8 @@ static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDe
// do socks negotiation
if (proxy.randomize_credentials) {
ProxyCredentials random_auth;
- random_auth.username = strprintf("%i", insecure_rand());
- random_auth.password = strprintf("%i", insecure_rand());
+ static std::atomic_int counter;
+ random_auth.username = random_auth.password = strprintf("%i", counter++);
if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))
return false;
} else {
@@ -618,8 +597,8 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
SplitHostPort(std::string(pszDest), port, strDest);
- proxyType nameProxy;
- GetNameProxy(nameProxy);
+ proxyType proxy;
+ GetNameProxy(proxy);
std::vector<CService> addrResolved;
if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy(), 256)) {
@@ -629,777 +608,48 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
}
}
- addr = CService("0.0.0.0:0");
+ addr = CService();
if (!HaveNameProxy())
return false;
- return ConnectThroughProxy(nameProxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed);
-}
-
-void CNetAddr::Init()
-{
- memset(ip, 0, sizeof(ip));
- scopeId = 0;
-}
-
-void CNetAddr::SetIP(const CNetAddr& ipIn)
-{
- memcpy(ip, ipIn.ip, sizeof(ip));
-}
-
-void CNetAddr::SetRaw(Network network, const uint8_t *ip_in)
-{
- switch(network)
- {
- case NET_IPV4:
- memcpy(ip, pchIPv4, 12);
- memcpy(ip+12, ip_in, 4);
- break;
- case NET_IPV6:
- memcpy(ip, ip_in, 16);
- break;
- default:
- assert(!"invalid network");
- }
-}
-
-static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
-
-bool CNetAddr::SetSpecial(const std::string &strName)
-{
- if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
- std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str());
- if (vchAddr.size() != 16-sizeof(pchOnionCat))
- return false;
- memcpy(ip, pchOnionCat, sizeof(pchOnionCat));
- for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++)
- ip[i + sizeof(pchOnionCat)] = vchAddr[i];
- return true;
- }
- return false;
-}
-
-CNetAddr::CNetAddr()
-{
- Init();
-}
-
-CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
-{
- SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr);
-}
-
-CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope)
-{
- SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr);
- scopeId = scope;
-}
-
-CNetAddr::CNetAddr(const char *pszIp)
-{
- Init();
- std::vector<CNetAddr> vIP;
- if (LookupHost(pszIp, vIP, 1, false))
- *this = vIP[0];
-}
-
-CNetAddr::CNetAddr(const std::string &strIp)
-{
- Init();
- std::vector<CNetAddr> vIP;
- if (LookupHost(strIp.c_str(), vIP, 1, false))
- *this = vIP[0];
-}
-
-unsigned int CNetAddr::GetByte(int n) const
-{
- return ip[15-n];
-}
-
-bool CNetAddr::IsIPv4() const
-{
- return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0);
-}
-
-bool CNetAddr::IsIPv6() const
-{
- return (!IsIPv4() && !IsTor());
-}
-
-bool CNetAddr::IsRFC1918() const
-{
- return IsIPv4() && (
- GetByte(3) == 10 ||
- (GetByte(3) == 192 && GetByte(2) == 168) ||
- (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31)));
-}
-
-bool CNetAddr::IsRFC2544() const
-{
- return IsIPv4() && GetByte(3) == 198 && (GetByte(2) == 18 || GetByte(2) == 19);
-}
-
-bool CNetAddr::IsRFC3927() const
-{
- return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
-}
-
-bool CNetAddr::IsRFC6598() const
-{
- return IsIPv4() && GetByte(3) == 100 && GetByte(2) >= 64 && GetByte(2) <= 127;
-}
-
-bool CNetAddr::IsRFC5737() const
-{
- return IsIPv4() && ((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) ||
- (GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) ||
- (GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113));
-}
-
-bool CNetAddr::IsRFC3849() const
-{
- return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8;
-}
-
-bool CNetAddr::IsRFC3964() const
-{
- return (GetByte(15) == 0x20 && GetByte(14) == 0x02);
-}
-
-bool CNetAddr::IsRFC6052() const
-{
- static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0};
- return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0);
-}
-
-bool CNetAddr::IsRFC4380() const
-{
- return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0);
-}
-
-bool CNetAddr::IsRFC4862() const
-{
- static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0};
- return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0);
-}
-
-bool CNetAddr::IsRFC4193() const
-{
- return ((GetByte(15) & 0xFE) == 0xFC);
-}
-
-bool CNetAddr::IsRFC6145() const
-{
- static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0};
- return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0);
-}
-
-bool CNetAddr::IsRFC4843() const
-{
- return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
-}
-
-bool CNetAddr::IsTor() const
-{
- return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
-}
-
-bool CNetAddr::IsLocal() const
-{
- // IPv4 loopback
- if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0))
- return true;
-
- // IPv6 loopback (::1/128)
- static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
- if (memcmp(ip, pchLocal, 16) == 0)
- return true;
-
- 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
- // of addr messages from versions before 0.2.9 checksum.
- // Two consecutive addr messages look like this:
- // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
- // so if the first length field is garbled, it reads the second batch
- // of addr misaligned by 3 bytes.
- if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
- return false;
-
- // unspecified IPv6 address (::/128)
- unsigned char ipNone[16] = {};
- if (memcmp(ip, ipNone, 16) == 0)
- return false;
-
- // documentation IPv6 address
- if (IsRFC3849())
- return false;
-
- if (IsIPv4())
- {
- // INADDR_NONE
- uint32_t ipNone = INADDR_NONE;
- if (memcmp(ip+12, &ipNone, 4) == 0)
- return false;
-
- // 0
- ipNone = 0;
- if (memcmp(ip+12, &ipNone, 4) == 0)
- return false;
- }
-
- return true;
-}
-
-bool CNetAddr::IsRoutable() const
-{
- return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal());
-}
-
-enum Network CNetAddr::GetNetwork() const
-{
- if (!IsRoutable())
- return NET_UNROUTABLE;
-
- if (IsIPv4())
- return NET_IPV4;
-
- if (IsTor())
- return NET_TOR;
-
- return NET_IPV6;
-}
-
-std::string CNetAddr::ToStringIP() const
-{
- if (IsTor())
- return EncodeBase32(&ip[6], 10) + ".onion";
- 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))
- return std::string(name);
- }
- if (IsIPv4())
- return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
- else
- return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
- GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12),
- GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8),
- GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4),
- GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0));
-}
-
-std::string CNetAddr::ToString() const
-{
- return ToStringIP();
-}
-
-bool operator==(const CNetAddr& a, const CNetAddr& b)
-{
- return (memcmp(a.ip, b.ip, 16) == 0);
-}
-
-bool operator!=(const CNetAddr& a, const CNetAddr& b)
-{
- return (memcmp(a.ip, b.ip, 16) != 0);
-}
-
-bool operator<(const CNetAddr& a, const CNetAddr& b)
-{
- return (memcmp(a.ip, b.ip, 16) < 0);
-}
-
-bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
-{
- if (!IsIPv4())
- return false;
- memcpy(pipv4Addr, ip+12, 4);
- return true;
-}
-
-bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
-{
- memcpy(pipv6Addr, ip, 16);
- return true;
-}
-
-// get canonical identifier of an address' group
-// no two connections will be attempted to addresses with the same group
-std::vector<unsigned char> CNetAddr::GetGroup() const
-{
- std::vector<unsigned char> vchRet;
- int nClass = NET_IPV6;
- int nStartByte = 0;
- int nBits = 16;
-
- // all local addresses belong to the same group
- if (IsLocal())
- {
- nClass = 255;
- nBits = 0;
- }
-
- // all unroutable addresses belong to the same group
- if (!IsRoutable())
- {
- nClass = NET_UNROUTABLE;
- nBits = 0;
- }
- // for IPv4 addresses, '1' + the 16 higher-order bits of the IP
- // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix
- else if (IsIPv4() || IsRFC6145() || IsRFC6052())
- {
- nClass = NET_IPV4;
- nStartByte = 12;
- }
- // for 6to4 tunnelled addresses, use the encapsulated IPv4 address
- else if (IsRFC3964())
- {
- nClass = NET_IPV4;
- nStartByte = 2;
- }
- // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address
- else if (IsRFC4380())
- {
- vchRet.push_back(NET_IPV4);
- vchRet.push_back(GetByte(3) ^ 0xFF);
- vchRet.push_back(GetByte(2) ^ 0xFF);
- return vchRet;
- }
- else if (IsTor())
- {
- nClass = NET_TOR;
- nStartByte = 6;
- nBits = 4;
- }
- // for he.net, use /36 groups
- else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
- nBits = 36;
- // for the rest of the IPv6 network, use /32 groups
- else
- nBits = 32;
-
- vchRet.push_back(nClass);
- while (nBits >= 8)
- {
- vchRet.push_back(GetByte(15 - nStartByte));
- nStartByte++;
- nBits -= 8;
- }
- if (nBits > 0)
- vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1));
-
- return vchRet;
-}
-
-uint64_t CNetAddr::GetHash() const
-{
- uint256 hash = Hash(&ip[0], &ip[16]);
- uint64_t nRet;
- memcpy(&nRet, &hash, sizeof(nRet));
- return nRet;
-}
-
-// private extensions to enum Network, only returned by GetExtNetwork,
-// and only used in GetReachabilityFrom
-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)
- return NET_UNKNOWN;
- if (addr->IsRFC4380())
- return NET_TEREDO;
- return addr->GetNetwork();
-}
-
-/** Calculates a metric for how reachable (*this) is from a given partner */
-int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
-{
- enum Reachability {
- REACH_UNREACHABLE,
- REACH_DEFAULT,
- REACH_TEREDO,
- REACH_IPV6_WEAK,
- REACH_IPV4,
- REACH_IPV6_STRONG,
- REACH_PRIVATE
- };
-
- if (!IsRoutable())
- return REACH_UNREACHABLE;
-
- int ourNet = GetExtNetwork(this);
- int theirNet = GetExtNetwork(paddrPartner);
- bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145();
-
- switch(theirNet) {
- case NET_IPV4:
- switch(ourNet) {
- default: return REACH_DEFAULT;
- case NET_IPV4: return REACH_IPV4;
- }
- case NET_IPV6:
- switch(ourNet) {
- default: return REACH_DEFAULT;
- case NET_TEREDO: return REACH_TEREDO;
- case NET_IPV4: return REACH_IPV4;
- case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled
- }
- case NET_TOR:
- switch(ourNet) {
- default: return REACH_DEFAULT;
- case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well
- case NET_TOR: return REACH_PRIVATE;
- }
- case NET_TEREDO:
- switch(ourNet) {
- default: return REACH_DEFAULT;
- case NET_TEREDO: return REACH_TEREDO;
- case NET_IPV6: return REACH_IPV6_WEAK;
- case NET_IPV4: return REACH_IPV4;
- }
- case NET_UNKNOWN:
- case NET_UNROUTABLE:
- default:
- switch(ourNet) {
- default: return REACH_DEFAULT;
- case NET_TEREDO: return REACH_TEREDO;
- case NET_IPV6: return REACH_IPV6_WEAK;
- case NET_IPV4: return REACH_IPV4;
- case NET_TOR: return REACH_PRIVATE; // either from Tor, or don't care about our address
- }
- }
-}
-
-void CService::Init()
-{
- port = 0;
-}
-
-CService::CService()
-{
- Init();
-}
-
-CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn)
-{
-}
-
-CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn)
-{
-}
-
-CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn)
-{
-}
-
-CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port))
-{
- assert(addr.sin_family == AF_INET);
-}
-
-CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr, addr.sin6_scope_id), port(ntohs(addr.sin6_port))
-{
- assert(addr.sin6_family == AF_INET6);
-}
-
-bool CService::SetSockAddr(const struct sockaddr *paddr)
-{
- switch (paddr->sa_family) {
- case AF_INET:
- *this = CService(*(const struct sockaddr_in*)paddr);
- return true;
- case AF_INET6:
- *this = CService(*(const struct sockaddr_in6*)paddr);
- return true;
- default:
- return false;
- }
-}
-
-CService::CService(const char *pszIpPort)
-{
- Init();
- CService ip;
- if (Lookup(pszIpPort, ip, 0, false))
- *this = ip;
-}
-
-CService::CService(const char *pszIpPort, int portDefault)
-{
- Init();
- CService ip;
- if (Lookup(pszIpPort, ip, portDefault, false))
- *this = ip;
-}
-
-CService::CService(const std::string &strIpPort)
-{
- Init();
- CService ip;
- if (Lookup(strIpPort.c_str(), ip, 0, false))
- *this = ip;
-}
-
-CService::CService(const std::string &strIpPort, int portDefault)
-{
- Init();
- CService ip;
- if (Lookup(strIpPort.c_str(), ip, portDefault, false))
- *this = ip;
-}
-
-unsigned short CService::GetPort() const
-{
- return port;
-}
-
-bool operator==(const CService& a, const CService& b)
-{
- return (CNetAddr)a == (CNetAddr)b && a.port == b.port;
-}
-
-bool operator!=(const CService& a, const CService& b)
-{
- return (CNetAddr)a != (CNetAddr)b || a.port != b.port;
-}
-
-bool operator<(const CService& a, const CService& b)
-{
- return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port);
-}
-
-bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
-{
- if (IsIPv4()) {
- if (*addrlen < (socklen_t)sizeof(struct sockaddr_in))
- return false;
- *addrlen = sizeof(struct sockaddr_in);
- struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr;
- memset(paddrin, 0, *addrlen);
- if (!GetInAddr(&paddrin->sin_addr))
- return false;
- paddrin->sin_family = AF_INET;
- paddrin->sin_port = htons(port);
- return true;
- }
- if (IsIPv6()) {
- if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6))
- return false;
- *addrlen = sizeof(struct sockaddr_in6);
- struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr;
- memset(paddrin6, 0, *addrlen);
- if (!GetIn6Addr(&paddrin6->sin6_addr))
- return false;
- paddrin6->sin6_scope_id = scopeId;
- paddrin6->sin6_family = AF_INET6;
- paddrin6->sin6_port = htons(port);
- return true;
- }
- return false;
+ return ConnectThroughProxy(proxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed);
}
-std::vector<unsigned char> CService::GetKey() const
-{
- std::vector<unsigned char> vKey;
- vKey.resize(18);
- memcpy(&vKey[0], ip, 16);
- vKey[16] = port / 0x100;
- vKey[17] = port & 0x0FF;
- return vKey;
-}
-
-std::string CService::ToStringPort() const
-{
- return strprintf("%u", port);
-}
-
-std::string CService::ToStringIPPort() const
-{
- if (IsIPv4() || IsTor()) {
- return ToStringIP() + ":" + ToStringPort();
- } else {
- return "[" + ToStringIP() + "]:" + ToStringPort();
- }
-}
-
-std::string CService::ToString() const
-{
- return ToStringIPPort();
-}
-
-void CService::SetPort(unsigned short portIn)
-{
- port = portIn;
-}
-
-CSubNet::CSubNet():
- valid(false)
-{
- memset(netmask, 0, sizeof(netmask));
-}
-
-CSubNet::CSubNet(const std::string &strSubnet)
+bool LookupSubNet(const char* pszName, CSubNet& ret)
{
+ std::string strSubnet(pszName);
size_t slash = strSubnet.find_last_of('/');
std::vector<CNetAddr> vIP;
- valid = true;
- // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address
- memset(netmask, 255, sizeof(netmask));
-
std::string strAddress = strSubnet.substr(0, slash);
if (LookupHost(strAddress.c_str(), vIP, 1, false))
{
- network = vIP[0];
+ CNetAddr network = vIP[0];
if (slash != strSubnet.npos)
{
std::string strNetmask = strSubnet.substr(slash + 1);
int32_t n;
// IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n
- const int astartofs = network.IsIPv4() ? 12 : 0;
- if (ParseInt32(strNetmask, &n)) // If valid number, assume /24 symtex
- {
- if(n >= 0 && n <= (128 - astartofs*8)) // Only valid if in range of bits of address
- {
- n += astartofs*8;
- // Clear bits [n..127]
- for (; n < 128; ++n)
- netmask[n>>3] &= ~(1<<(7-(n&7)));
- }
- else
- {
- valid = false;
- }
+ if (ParseInt32(strNetmask, &n)) { // If valid number, assume /24 syntax
+ ret = CSubNet(network, n);
+ return ret.IsValid();
}
else // If not a valid number, try full netmask syntax
{
- if (LookupHost(strNetmask.c_str(), vIP, 1, false)) // Never allow lookup for netmask
- {
- // Copy only the *last* four bytes in case of IPv4, the rest of the mask should stay 1's as
- // we don't want pchIPv4 to be part of the mask.
- for(int x=astartofs; x<16; ++x)
- netmask[x] = vIP[0].ip[x];
- }
- else
- {
- valid = false;
+ // Never allow lookup for netmask
+ if (LookupHost(strNetmask.c_str(), vIP, 1, false)) {
+ ret = CSubNet(network, vIP[0]);
+ return ret.IsValid();
}
}
}
- }
- else
- {
- valid = false;
- }
-
- // Normalize network according to netmask
- for(int x=0; x<16; ++x)
- network.ip[x] &= netmask[x];
-}
-
-CSubNet::CSubNet(const CNetAddr &addr):
- valid(addr.IsValid())
-{
- memset(netmask, 255, sizeof(netmask));
- network = addr;
-}
-
-bool CSubNet::Match(const CNetAddr &addr) const
-{
- if (!valid || !addr.IsValid())
- return false;
- for(int x=0; x<16; ++x)
- if ((addr.ip[x] & netmask[x]) != network.ip[x])
- return false;
- return true;
-}
-
-static inline int NetmaskBits(uint8_t x)
-{
- switch(x) {
- case 0x00: return 0; break;
- case 0x80: return 1; break;
- case 0xc0: return 2; break;
- case 0xe0: return 3; break;
- case 0xf0: return 4; break;
- case 0xf8: return 5; break;
- case 0xfc: return 6; break;
- case 0xfe: return 7; break;
- case 0xff: return 8; break;
- default: return -1; break;
- }
-}
-
-std::string CSubNet::ToString() const
-{
- /* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */
- int cidr = 0;
- bool valid_cidr = true;
- int n = network.IsIPv4() ? 12 : 0;
- for (; n < 16 && netmask[n] == 0xff; ++n)
- cidr += 8;
- if (n < 16) {
- int bits = NetmaskBits(netmask[n]);
- if (bits < 0)
- valid_cidr = false;
else
- cidr += bits;
- ++n;
- }
- for (; n < 16 && valid_cidr; ++n)
- if (netmask[n] != 0x00)
- valid_cidr = false;
-
- /* Format output */
- std::string strNetmask;
- if (valid_cidr) {
- strNetmask = strprintf("%u", cidr);
- } else {
- if (network.IsIPv4())
- strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]);
- else
- strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
- netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3],
- netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7],
- netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11],
- netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]);
+ {
+ ret = CSubNet(network);
+ return ret.IsValid();
+ }
}
-
- return network.ToString() + "/" + strNetmask;
-}
-
-bool CSubNet::IsValid() const
-{
- return valid;
-}
-
-bool operator==(const CSubNet& a, const CSubNet& b)
-{
- return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16);
-}
-
-bool operator!=(const CSubNet& a, const CSubNet& b)
-{
- return !(a==b);
-}
-
-bool operator<(const CSubNet& a, const CSubNet& b)
-{
- return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
+ return false;
}
#ifdef WIN32
@@ -1477,3 +727,8 @@ bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking)
return true;
}
+
+void InterruptSocks5(bool interrupt)
+{
+ interruptSocks5Recv = interrupt;
+}
diff --git a/src/netbase.h b/src/netbase.h
index 65187a17cf..dd33b6e47e 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -10,6 +10,7 @@
#endif
#include "compat.h"
+#include "netaddress.h"
#include "serialize.h"
#include <stdint.h>
@@ -24,173 +25,11 @@ static const int DEFAULT_CONNECT_TIMEOUT = 5000;
//! -dns default
static const int DEFAULT_NAME_LOOKUP = true;
-#ifdef WIN32
-// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error
-#undef SetPort
-#endif
-
-enum Network
-{
- NET_UNROUTABLE = 0,
- NET_IPV4,
- NET_IPV6,
- NET_TOR,
-
- NET_MAX,
-};
-
-/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */
-class CNetAddr
-{
- protected:
- unsigned char ip[16]; // in network byte order
- uint32_t scopeId; // for scoped/link-local ipv6 addresses
-
- public:
- CNetAddr();
- CNetAddr(const struct in_addr& ipv4Addr);
- explicit CNetAddr(const char *pszIp);
- explicit CNetAddr(const std::string &strIp);
- void Init();
- void SetIP(const CNetAddr& ip);
-
- /**
- * Set raw IPv4 or IPv6 address (in network byte order)
- * @note Only NET_IPV4 and NET_IPV6 are allowed for network.
- */
- void SetRaw(Network network, const uint8_t *data);
-
- 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 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)
- bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
- bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16)
- bool IsRFC4193() const; // IPv6 unique local (FC00::/7)
- bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32)
- bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28)
- bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
- bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
- bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
- bool IsTor() const;
- bool IsLocal() const;
- bool IsRoutable() const;
- bool IsValid() const;
- bool IsMulticast() const;
- enum Network GetNetwork() const;
- std::string ToString() const;
- std::string ToStringIP() const;
- unsigned int GetByte(int n) const;
- uint64_t GetHash() const;
- bool GetInAddr(struct in_addr* pipv4Addr) const;
- std::vector<unsigned char> GetGroup() const;
- int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;
-
- 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);
- friend bool operator!=(const CNetAddr& a, const CNetAddr& b);
- friend bool operator<(const CNetAddr& a, const CNetAddr& b);
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(FLATDATA(ip));
- }
-
- friend class CSubNet;
-};
-
-class CSubNet
-{
- protected:
- /// Network (base) address
- CNetAddr network;
- /// Netmask, in network byte order
- uint8_t netmask[16];
- /// Is this value valid? (only used to signal parse errors)
- bool valid;
-
- public:
- CSubNet();
- explicit CSubNet(const std::string &strSubnet);
-
- //constructor for single ip subnet (<ipv4>/32 or <ipv6>/128)
- explicit CSubNet(const CNetAddr &addr);
-
- bool Match(const CNetAddr &addr) const;
-
- std::string ToString() const;
- bool IsValid() const;
-
- friend bool operator==(const CSubNet& a, const CSubNet& b);
- friend bool operator!=(const CSubNet& a, const CSubNet& b);
- friend bool operator<(const CSubNet& a, const CSubNet& b);
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(network);
- READWRITE(FLATDATA(netmask));
- READWRITE(FLATDATA(valid));
- }
-};
-
-/** A combination of a network address (CNetAddr) and a (TCP) port */
-class CService : public CNetAddr
-{
- protected:
- unsigned short port; // host order
-
- public:
- 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 char *pszIpPort, int portDefault);
- explicit CService(const char *pszIpPort);
- explicit CService(const std::string& strIpPort, int portDefault);
- explicit CService(const std::string& strIpPort);
- 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);
- friend bool operator==(const CService& a, const CService& b);
- friend bool operator!=(const CService& a, const CService& b);
- friend bool operator<(const CService& a, const CService& b);
- std::vector<unsigned char> GetKey() const;
- std::string ToString() const;
- std::string ToStringPort() const;
- std::string ToStringIPPort() const;
-
- CService(const struct in6_addr& ipv6Addr, unsigned short port);
- CService(const struct sockaddr_in6& addr);
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(FLATDATA(ip));
- unsigned short portN = htons(port);
- READWRITE(FLATDATA(portN));
- if (ser_action.ForRead())
- port = ntohs(portN);
- }
-};
-
class proxyType
{
public:
proxyType(): randomize_credentials(false) {}
- proxyType(const CService &proxy, bool randomize_credentials=false): proxy(proxy), randomize_credentials(randomize_credentials) {}
+ proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}
bool IsValid() const { return proxy.IsValid(); }
@@ -207,9 +46,11 @@ bool IsProxy(const CNetAddr &addr);
bool SetNameProxy(const proxyType &addrProxy);
bool HaveNameProxy();
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);
-bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0);
+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);
/** Return readable error string for a network error code */
@@ -222,5 +63,6 @@ bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking);
* Convert milliseconds to a struct timeval for e.g. select.
*/
struct timeval MillisToTimeval(int64_t nTimeout);
+void InterruptSocks5(bool interrupt);
#endif // BITCOIN_NETBASE_H
diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h
new file mode 100644
index 0000000000..8e8a6e4a02
--- /dev/null
+++ b/src/netmessagemaker.h
@@ -0,0 +1,36 @@
+// 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_NETMESSAGEMAKER_H
+#define BITCOIN_NETMESSAGEMAKER_H
+
+#include "net.h"
+#include "serialize.h"
+
+class CNetMsgMaker
+{
+public:
+ CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
+
+ template <typename... Args>
+ CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args) const
+ {
+ CSerializedNetMsg msg;
+ msg.command = std::move(sCommand);
+ CVectorWriter{ SER_NETWORK, nFlags | nVersion, msg.data, 0, std::forward<Args>(args)... };
+ return msg;
+ }
+
+ template <typename... Args>
+ CSerializedNetMsg Make(std::string sCommand, Args&&... args) const
+ {
+ return Make(0, std::move(sCommand), std::forward<Args>(args)...);
+ }
+
+private:
+ const int nVersion;
+};
+
+#endif // BITCOIN_NETMESSAGEMAKER_H
diff --git a/src/noui.cpp b/src/noui.cpp
index 0d9207c11a..4bfb75fa29 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// 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.
diff --git a/src/amount.cpp b/src/policy/feerate.cpp
index 7b8618de33..a089c02284 100644
--- a/src/amount.cpp
+++ b/src/policy/feerate.cpp
@@ -1,9 +1,9 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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 "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..e82268b095
--- /dev/null
+++ b/src/policy/feerate.h
@@ -0,0 +1,54 @@
+// 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) { }
+ 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_POLICY_FEERATE_H
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 7b0e8b7d08..bd169f875a 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin developers
+// 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.
@@ -7,17 +7,123 @@
#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, std::string _dataTypeString)
+/**
+ * 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:
+ /**
+ * Create new TxConfirmStats. 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
+ */
+ TxConfirmStats(const 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) const;
+
+ /** Return the max number of confirms we're tracking */
+ unsigned int GetMaxConfirms() const { return 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);
+};
+
+
+TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
+ unsigned int maxConfirms, double _decay)
{
decay = _decay;
- dataTypeString = _dataTypeString;
for (unsigned int i = 0; i < defaultBuckets.size(); i++) {
buckets.push_back(defaultBuckets[i]);
bucketMap[defaultBuckets[i]] = i;
@@ -78,7 +184,7 @@ void TxConfirmStats::UpdateMovingAverages()
// returns -1 on error conditions
double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
double successBreakPoint, bool requireGreater,
- unsigned int nBlockHeight)
+ unsigned int nBlockHeight) const
{
// Counters for a bucket (or range of buckets)
double nConf = 0; // Number of tx's confirmed within the confTarget
@@ -87,10 +193,10 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
int maxbucketindex = buckets.size() - 1;
- // requireGreater means we are looking for the lowest fee/priority such that all higher
- // values pass, so we start at maxbucketindex (highest fee) and look at successively
+ // requireGreater means we are looking for the lowest feerate such that all higher
+ // values pass, so we start at maxbucketindex (highest feerate) and look at successively
// smaller buckets until we reach failure. Otherwise, we are looking for the highest
- // fee/priority such that all lower values fail, and we go in the opposite direction.
+ // feerate such that all lower values fail, and we go in the opposite direction.
unsigned int startbucket = requireGreater ? maxbucketindex : 0;
int step = requireGreater ? -1 : 1;
@@ -107,7 +213,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
bool foundAnswer = false;
unsigned int bins = unconfTxs.size();
- // Start counting from highest(default) or lowest fee/pri transactions
+ // Start counting from highest(default) or lowest feerate transactions
for (int bucket = startbucket; bucket >= 0 && bucket <= maxbucketindex; bucket += step) {
curFarBucket = bucket;
nConf += confAvg[confTarget - 1][bucket];
@@ -145,8 +251,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
double median = -1;
double txSum = 0;
- // Calculate the "average" fee of the best bucket range that met success conditions
- // Find the bucket with the median transaction and then report the average fee from that bucket
+ // Calculate the "average" feerate of the best bucket range that met success conditions
+ // 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;
@@ -166,15 +272,15 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
}
}
- LogPrint("estimatefee", "%3d: For conf success %s %4.2f need %s %s: %12.5g from buckets %8g - %8g Cur Bucket stats %6.2f%% %8.1f/(%.1f+%d mempool)\n",
- confTarget, requireGreater ? ">" : "<", successBreakPoint, dataTypeString,
+ LogPrint(BCLog::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);
return median;
}
-void TxConfirmStats::Write(CAutoFile& fileout)
+void TxConfirmStats::Write(CAutoFile& fileout) const
{
fileout << decay;
fileout << buckets;
@@ -200,10 +306,10 @@ void TxConfirmStats::Read(CAutoFile& filein)
filein >> fileBuckets;
numBuckets = fileBuckets.size();
if (numBuckets <= 1 || numBuckets > 1000)
- throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 fee/pri buckets");
+ throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
filein >> fileAvg;
if (fileAvg.size() != numBuckets)
- throw std::runtime_error("Corrupt estimates file. Mismatch in fee/pri average bucket count");
+ throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count");
filein >> fileTxCtAvg;
if (fileTxCtAvg.size() != numBuckets)
throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
@@ -213,9 +319,9 @@ void TxConfirmStats::Read(CAutoFile& filein)
throw std::runtime_error("Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
for (unsigned int i = 0; i < maxConfirms; i++) {
if (fileConfAvg[i].size() != numBuckets)
- throw std::runtime_error("Corrupt estimates file. Mismatch in fee/pri conf average bucket count");
+ throw std::runtime_error("Corrupt estimates file. Mismatch in feerate conf average bucket count");
}
- // Now that we've processed the entire fee estimate data file and not
+ // 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;
@@ -242,8 +348,8 @@ void TxConfirmStats::Read(CAutoFile& filein)
for (unsigned int i = 0; i < buckets.size(); i++)
bucketMap[buckets[i]] = i;
- LogPrint("estimatefee", "Reading estimates: %u %s buckets counting confirms up to %u blocks\n",
- numBuckets, dataTypeString, maxConfirms);
+ LogPrint(BCLog::ESTIMATEFEE, "Reading estimates: %u buckets counting confirms up to %u blocks\n",
+ numBuckets, maxConfirms);
}
unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
@@ -251,7 +357,6 @@ unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
unsigned int bucketindex = bucketMap.lower_bound(val)->second;
unsigned int blockIndex = nBlockHeight % unconfTxs.size();
unconfTxs[blockIndex][bucketindex]++;
- LogPrint("estimatefee", "adding to %s", dataTypeString);
return bucketindex;
}
@@ -262,181 +367,128 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
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);
+ }
}
}
-void CBlockPolicyEstimator::removeTx(uint256 hash)
+// This function is called from CTxMemPool::removeUnchecked to ensure
+// txs removed from the mempool for any reason are no longer
+// 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)
{
+ LOCK(cs_feeEstimator);
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
- if (pos == mapMemPoolTxs.end()) {
- LogPrint("estimatefee", "Blockpolicy error mempool tx %s not found for removeTx\n",
- hash.ToString().c_str());
- return;
+ if (pos != mapMemPoolTxs.end()) {
+ feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex);
+ mapMemPoolTxs.erase(hash);
+ return true;
+ } else {
+ return false;
}
- TxConfirmStats *stats = pos->second.stats;
- unsigned int entryHeight = pos->second.blockHeight;
- unsigned int bucketIndex = pos->second.bucketIndex;
-
- if (stats != NULL)
- stats->removeTx(entryHeight, nBestSeenHeight, bucketIndex);
- mapMemPoolTxs.erase(hash);
}
-CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee)
- : nBestSeenHeight(0)
+CBlockPolicyEstimator::CBlockPolicyEstimator()
+ : nBestSeenHeight(0), trackedTxs(0), untrackedTxs(0)
{
- minTrackedFee = _minRelayFee < CFeeRate(MIN_FEERATE) ? CFeeRate(MIN_FEERATE) : _minRelayFee;
+ static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
+ minTrackedFee = CFeeRate(MIN_BUCKET_FEERATE);
std::vector<double> vfeelist;
- for (double bucketBoundary = minTrackedFee.GetFeePerK(); bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) {
+ for (double bucketBoundary = minTrackedFee.GetFeePerK(); bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING) {
vfeelist.push_back(bucketBoundary);
}
vfeelist.push_back(INF_FEERATE);
- feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "FeeRate");
-
- minTrackedPriority = AllowFreeThreshold() < MIN_PRIORITY ? MIN_PRIORITY : AllowFreeThreshold();
- std::vector<double> vprilist;
- for (double bucketBoundary = minTrackedPriority; bucketBoundary <= MAX_PRIORITY; bucketBoundary *= PRI_SPACING) {
- vprilist.push_back(bucketBoundary);
- }
- vprilist.push_back(INF_PRIORITY);
- priStats.Initialize(vprilist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "Priority");
-
- feeUnlikely = CFeeRate(0);
- feeLikely = CFeeRate(INF_FEERATE);
- priUnlikely = 0;
- priLikely = INF_PRIORITY;
-}
-
-bool CBlockPolicyEstimator::isFeeDataPoint(const CFeeRate &fee, double pri)
-{
- if ((pri < minTrackedPriority && fee >= minTrackedFee) ||
- (pri < priUnlikely && fee > feeLikely)) {
- return true;
- }
- return false;
+ feeStats = new TxConfirmStats(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY);
}
-bool CBlockPolicyEstimator::isPriDataPoint(const CFeeRate &fee, double pri)
+CBlockPolicyEstimator::~CBlockPolicyEstimator()
{
- if ((fee < minTrackedFee && pri >= minTrackedPriority) ||
- (fee < feeUnlikely && pri > priLikely)) {
- return true;
- }
- return false;
+ delete feeStats;
}
-void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate)
+void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
{
+ LOCK(cs_feeEstimator);
unsigned int txHeight = entry.GetHeight();
uint256 hash = entry.GetTx().GetHash();
- if (mapMemPoolTxs[hash].stats != NULL) {
- LogPrint("estimatefee", "Blockpolicy error mempool tx %s already being tracked\n",
+ if (mapMemPoolTxs.count(hash)) {
+ LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n",
hash.ToString().c_str());
return;
}
- if (txHeight < nBestSeenHeight) {
+ if (txHeight != nBestSeenHeight) {
// Ignore side chains and re-orgs; assuming they are random they don't
// affect the estimate. We'll potentially double count transactions in 1-block reorgs.
+ // Ignore txs if BlockPolicyEstimator is not in sync with chainActive.Tip().
+ // It will be synced next time a block is processed.
return;
}
// Only want to be updating estimates when our blockchain is synced,
// otherwise we'll miscalculate how many blocks its taking to get included.
- if (!fCurrentEstimate)
- return;
-
- if (!entry.WasClearAtEntry()) {
- // This transaction depends on other transactions in the mempool to
- // be included in a block before it will be able to be included, so
- // we shouldn't include it in our calculations
+ if (!validFeeEstimate) {
+ untrackedTxs++;
return;
}
+ trackedTxs++;
- // Fees are stored and reported as BTC-per-kb:
+ // Feerates are stored and reported as BTC-per-kb:
CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
- // Want the priority of the tx at confirmation. However we don't know
- // what that will be and its too hard to continue updating it
- // so use starting priority as a proxy
- double curPri = entry.GetPriority(txHeight);
mapMemPoolTxs[hash].blockHeight = txHeight;
-
- LogPrint("estimatefee", "Blockpolicy mempool tx %s ", hash.ToString().substr(0,10));
- // Record this as a priority estimate
- if (entry.GetFee() == 0 || isPriDataPoint(feeRate, curPri)) {
- mapMemPoolTxs[hash].stats = &priStats;
- mapMemPoolTxs[hash].bucketIndex = priStats.NewTx(txHeight, curPri);
- }
- // Record this as a fee estimate
- else if (isFeeDataPoint(feeRate, curPri)) {
- mapMemPoolTxs[hash].stats = &feeStats;
- mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK());
- }
- else {
- LogPrint("estimatefee", "not adding");
- }
- LogPrint("estimatefee", "\n");
+ mapMemPoolTxs[hash].bucketIndex = feeStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
}
-void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry)
+bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry)
{
- if (!entry.WasClearAtEntry()) {
- // This transaction depended on other transactions in the mempool to
- // be included in a block before it was able to be included, so
- // we shouldn't include it in our calculations
- return;
+ if (!removeTx(entry->GetTx().GetHash())) {
+ // This transaction wasn't being tracked for fee estimation
+ return false;
}
// How many blocks did it take for miners to include this transaction?
// blocksToConfirm is 1-based, so a transaction included in the earliest
// possible block has confirmation count of 1
- int blocksToConfirm = nBlockHeight - entry.GetHeight();
+ int blocksToConfirm = nBlockHeight - entry->GetHeight();
if (blocksToConfirm <= 0) {
// This can't happen because we don't process transactions from a block with a height
// lower than our greatest seen height
- LogPrint("estimatefee", "Blockpolicy error Transaction had negative blocksToConfirm\n");
- return;
+ LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error Transaction had negative blocksToConfirm\n");
+ return false;
}
- // Fees are stored and reported as BTC-per-kb:
- CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
-
- // Want the priority of the tx at confirmation. The priority when it
- // entered the mempool could easily be very small and change quickly
- double curPri = entry.GetPriority(nBlockHeight);
+ // Feerates are stored and reported as BTC-per-kb:
+ CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());
- // Record this as a priority estimate
- if (entry.GetFee() == 0 || isPriDataPoint(feeRate, curPri)) {
- priStats.Record(blocksToConfirm, curPri);
- }
- // Record this as a fee estimate
- else if (isFeeDataPoint(feeRate, curPri)) {
- feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK());
- }
+ feeStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
+ return true;
}
void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
- std::vector<CTxMemPoolEntry>& entries, bool fCurrentEstimate)
+ 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.
@@ -445,60 +497,41 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
// transaction fees."
return;
}
- nBestSeenHeight = nBlockHeight;
- // Only want to be updating estimates when our blockchain is synced,
- // otherwise we'll miscalculate how many blocks its taking to get included.
- if (!fCurrentEstimate)
- return;
+ // Must update nBestSeenHeight in sync with ClearCurrent so that
+ // calls to removeTx (via processBlockTx) correctly calculate age
+ // of unconfirmed txs to remove from tracking.
+ nBestSeenHeight = nBlockHeight;
- // Update the dynamic cutoffs
- // a fee/priority is "likely" the reason your tx was included in a block if >85% of such tx's
- // were confirmed in 2 blocks and is "unlikely" if <50% were confirmed in 10 blocks
- LogPrint("estimatefee", "Blockpolicy recalculating dynamic cutoffs:\n");
- priLikely = priStats.EstimateMedianVal(2, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBlockHeight);
- if (priLikely == -1)
- priLikely = INF_PRIORITY;
-
- double feeLikelyEst = feeStats.EstimateMedianVal(2, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBlockHeight);
- if (feeLikelyEst == -1)
- feeLikely = CFeeRate(INF_FEERATE);
- else
- feeLikely = CFeeRate(feeLikelyEst);
-
- priUnlikely = priStats.EstimateMedianVal(10, SUFFICIENT_PRITXS, UNLIKELY_PCT, false, nBlockHeight);
- if (priUnlikely == -1)
- priUnlikely = 0;
-
- double feeUnlikelyEst = feeStats.EstimateMedianVal(10, SUFFICIENT_FEETXS, UNLIKELY_PCT, false, nBlockHeight);
- if (feeUnlikelyEst == -1)
- feeUnlikely = CFeeRate(0);
- else
- feeUnlikely = CFeeRate(feeUnlikelyEst);
-
- // Clear the current block states
- feeStats.ClearCurrent(nBlockHeight);
- priStats.ClearCurrent(nBlockHeight);
+ // Clear the current block state and update unconfirmed circular buffer
+ feeStats->ClearCurrent(nBlockHeight);
+ unsigned int countedTxs = 0;
// Repopulate the current block states
- for (unsigned int i = 0; i < entries.size(); i++)
- processBlockTx(nBlockHeight, entries[i]);
+ for (unsigned int i = 0; i < entries.size(); i++) {
+ if (processBlockTx(nBlockHeight, entries[i]))
+ countedTxs++;
+ }
- // Update all exponential averages with the current block states
- feeStats.UpdateMovingAverages();
- priStats.UpdateMovingAverages();
+ // Update all exponential averages with the current block state
+ feeStats->UpdateMovingAverages();
- LogPrint("estimatefee", "Blockpolicy after updating estimates for %u confirmed entries, new mempool map size %u\n",
- entries.size(), mapMemPoolTxs.size());
+ LogPrint(BCLog::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());
+
+ trackedTxs = 0;
+ untrackedTxs = 0;
}
-CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget)
+CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) const
{
+ LOCK(cs_feeEstimator);
// Return failure if trying to analyze a target we're not tracking
- if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms())
+ // It's not possible to get reasonable estimates for confTarget of 1
+ if (confTarget <= 1 || (unsigned int)confTarget > feeStats->GetMaxConfirms())
return CFeeRate(0);
- double median = feeStats.EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
+ double median = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
if (median < 0)
return CFeeRate(0);
@@ -506,23 +539,33 @@ CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget)
return CFeeRate(median);
}
-CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
+CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) 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);
double median = -1;
- while (median < 0 && (unsigned int)confTarget <= feeStats.GetMaxConfirms()) {
- median = feeStats.EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
- }
+
+ {
+ LOCK(cs_feeEstimator);
+
+ // Return failure if trying to analyze a target we're not tracking
+ if (confTarget <= 0 || (unsigned int)confTarget > feeStats->GetMaxConfirms())
+ return CFeeRate(0);
+
+ // It's not possible to get reasonable estimates for confTarget of 1
+ if (confTarget == 1)
+ confTarget = 2;
+
+ while (median < 0 && (unsigned int)confTarget <= feeStats->GetMaxConfirms()) {
+ median = feeStats->EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
+ }
+ } // Must unlock cs_feeEstimator before taking mempool locks
if (answerFoundAtTarget)
*answerFoundAtTarget = confTarget - 1;
- // If mempool is limiting txs , return at least the min fee from the mempool
+ // 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);
@@ -533,60 +576,47 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
return CFeeRate(median);
}
-double CBlockPolicyEstimator::estimatePriority(int confTarget)
-{
- // Return failure if trying to analyze a target we're not tracking
- if (confTarget <= 0 || (unsigned int)confTarget > priStats.GetMaxConfirms())
- return -1;
-
- return priStats.EstimateMedianVal(confTarget, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
-}
-
-double CBlockPolicyEstimator::estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
-{
- if (answerFoundAtTarget)
- *answerFoundAtTarget = confTarget;
- // Return failure if trying to analyze a target we're not tracking
- if (confTarget <= 0 || (unsigned int)confTarget > priStats.GetMaxConfirms())
- return -1;
-
- // 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;
-
- double median = -1;
- while (median < 0 && (unsigned int)confTarget <= priStats.GetMaxConfirms()) {
- median = priStats.EstimateMedianVal(confTarget++, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
- }
-
- if (answerFoundAtTarget)
- *answerFoundAtTarget = confTarget - 1;
-
- return median;
-}
-
-void CBlockPolicyEstimator::Write(CAutoFile& fileout)
+bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
{
- fileout << nBestSeenHeight;
- feeStats.Write(fileout);
- priStats.Write(fileout);
+ try {
+ LOCK(cs_feeEstimator);
+ fileout << 139900; // version required to read: 0.13.99 or later
+ fileout << CLIENT_VERSION; // version that wrote the file
+ fileout << nBestSeenHeight;
+ feeStats->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)
+bool CBlockPolicyEstimator::Read(CAutoFile& filein)
{
- int nFileBestSeenHeight;
- filein >> nFileBestSeenHeight;
- feeStats.Read(filein);
- priStats.Read(filein);
- nBestSeenHeight = nFileBestSeenHeight;
+ try {
+ LOCK(cs_feeEstimator);
+ int nVersionRequired, nVersionThatWrote, nFileBestSeenHeight;
+ filein >> nVersionRequired >> nVersionThatWrote;
+ if (nVersionRequired > CLIENT_VERSION)
+ return error("CBlockPolicyEstimator::Read(): up-version (%d) fee estimate file", nVersionRequired);
+ filein >> nFileBestSeenHeight;
+ feeStats->Read(filein);
+ nBestSeenHeight = nFileBestSeenHeight;
+ // if nVersionThatWrote < 139900 then another TxConfirmStats (for priority) follows but can be ignored.
+ }
+ catch (const std::exception&) {
+ LogPrintf("CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal)\n");
+ return false;
+ }
+ return true;
}
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
{
- CAmount minFeeLimit = minIncrementalFee.GetFeePerK() / 2;
+ 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_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING) {
feeset.insert(bucketBoundary);
}
}
@@ -594,7 +624,7 @@ FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
CAmount FeeFilterRounder::round(CAmount currentMinFee)
{
std::set<double>::iterator it = feeset.lower_bound(currentMinFee);
- if ((it != feeset.begin() && insecure_rand() % 3 != 0) || it == feeset.end()) {
+ if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {
it--;
}
return *it;
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 463f62f710..15876574d2 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -1,12 +1,15 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin developers
+// 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_POLICYESTIMATOR_H
#define BITCOIN_POLICYESTIMATOR_H
#include "amount.h"
+#include "feerate.h"
#include "uint256.h"
+#include "random.h"
+#include "sync.h"
#include <map>
#include <string>
@@ -16,202 +19,79 @@ class CAutoFile;
class CFeeRate;
class CTxMemPoolEntry;
class CTxMemPool;
+class TxConfirmStats;
/** \class CBlockPolicyEstimator
- * The BlockPolicyEstimator is used for estimating the fee or priority needed
+ * The BlockPolicyEstimator is used for estimating the feerate needed
* for a transaction to be included in a block within a certain number of
* blocks.
*
* At a high level the algorithm works by grouping transactions into buckets
- * based on having similar priorities or fees and then tracking how long it
+ * based on having similar feerates and then tracking how long it
* takes transactions in the various buckets to be mined. It operates under
- * the assumption that in general transactions of higher fee/priority will be
- * included in blocks before transactions of lower fee/priority. So for
- * example if you wanted to know what fee you should put on a transaction to
+ * the assumption that in general transactions of higher feerate will be
+ * included in blocks before transactions of lower feerate. So for
+ * example if you wanted to know what feerate you should put on a transaction to
* be included in a block within the next 5 blocks, you would start by looking
- * at the bucket with the highest fee transactions and verifying that a
+ * at the bucket with the highest feerate transactions and verifying that a
* sufficiently high percentage of them were confirmed within 5 blocks and
- * then you would look at the next highest fee bucket, and so on, stopping at
- * the last bucket to pass the test. The average fee of transactions in this
- * bucket will give you an indication of the lowest fee you can put on a
+ * then you would look at the next highest feerate bucket, and so on, stopping at
+ * the last bucket to pass the test. The average feerate of transactions in this
+ * bucket will give you an indication of the lowest feerate you can put on a
* transaction and still have a sufficiently high chance of being confirmed
* within your desired 5 blocks.
*
- * When a transaction enters the mempool or is included within a block we
- * decide whether it can be used as a data point for fee estimation, priority
- * estimation or neither. If the value of exactly one of those properties was
- * below the required minimum it can be used to estimate the other. In
- * addition, if a priori our estimation code would indicate that the
- * transaction would be much more quickly included in a block because of one
- * of the properties compared to the other, we can also decide to use it as
- * an estimate for that property.
- *
- * Here is a brief description of the implementation for fee estimation.
- * When a transaction that counts for fee estimation enters the mempool, we
+ * 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 fee
+ * 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 fee
+ * 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 fee bucket when calculating
+ * 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 two instances of this class, one to track transactions
- * that were included in a block due to fee, and one for tx's included due to
- * priority. We will lump transactions into a bucket according to their approximate
- * fee or priority and then track how long it took for those txs to be included in a block
- *
- * The tracking of unconfirmed (mempool) transactions is completely independent of the
- * historical tracking of transactions that have been confirmed in a block.
- */
-class TxConfirmStats
-{
-private:
- //Define the buckets we will group transactions into (both fee buckets and priority buckets)
- std::vector<double> buckets; // The upper-bound of the range for the bucket (inclusive)
- std::map<double, unsigned int> bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
-
- // For each bucket X:
- // Count the total # of txs in each bucket
- // Track the historical moving average of this total over blocks
- std::vector<double> txCtAvg;
- // and 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 priority/fee of all tx's in each bucket
- // Track the historical moving average of this total over blocks
- std::vector<double> avg;
- // and calculate the total for the current block to update the moving average
- std::vector<double> curBlockVal;
-
- // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
- // Combine the total value with the tx counts to calculate the avg fee/priority per bucket
-
- std::string dataTypeString;
- double decay;
-
- // Mempool counts of outstanding transactions
- // For each bucket X, track the number of transactions in the mempool
- // that are unconfirmed for each possible confirmation value Y
- std::vector<std::vector<int> > unconfTxs; //unconfTxs[Y][X]
- // transactions still unconfirmed after MAX_CONFIRMS for each bucket
- std::vector<int> oldUnconfTxs;
-
-public:
- /**
- * Initialize the data structures. This is called by BlockPolicyEstimator's
- * constructor with default values.
- * @param defaultBuckets contains the upper limits for the bucket boundaries
- * @param maxConfirms max number of confirms to track
- * @param decay how much to decay the historical moving average per block
- * @param dataTypeString for logging purposes
- */
- void Initialize(std::vector<double>& defaultBuckets, unsigned int maxConfirms, double decay, std::string dataTypeString);
-
- /** Clear the state of the curBlock variables to start counting for the new block */
- void ClearCurrent(unsigned int nBlockHeight);
-
- /**
- * Record a new transaction data point in the current block stats
- * @param blocksToConfirm the number of blocks it took this transaction to confirm
- * @param val either the fee or the priority when entered of the transaction
- * @warning blocksToConfirm is 1-based and has to be >= 1
- */
- void Record(int blocksToConfirm, double val);
-
- /** Record a new transaction entering the mempool*/
- unsigned int NewTx(unsigned int nBlockHeight, double val);
-
- /** Remove a transaction from mempool tracking stats*/
- void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,
- unsigned int bucketIndex);
-
- /** Update our estimates by decaying our historical moving average and updating
- with the data gathered from the current block */
- void UpdateMovingAverages();
-
- /**
- * Calculate a fee or priority estimate. Find the lowest value bucket (or range of buckets
- * to make sure we have enough data points) whose transactions still have sufficient likelihood
- * of being confirmed within the target number of confirmations
- * @param confTarget target number of confirmations
- * @param sufficientTxVal required average number of transactions per block in a bucket range
- * @param minSuccess the success probability we require
- * @param requireGreater return the lowest fee/pri such that all higher values pass minSuccess OR
- * return the highest fee/pri such that all lower values fail minSuccess
- * @param nBlockHeight the current block height
- */
- double EstimateMedianVal(int confTarget, double sufficientTxVal,
- double minSuccess, bool requireGreater, unsigned int nBlockHeight);
-
- /** Return the max number of confirms we're tracking */
- unsigned int GetMaxConfirms() { return confAvg.size(); }
-
- /** Write state of estimation data to a file*/
- void Write(CAutoFile& fileout);
-
- /**
- * Read saved state of estimation data from a file and replace all internal data structures and
- * variables with this state.
- */
- void Read(CAutoFile& filein);
-};
-
-
-
/** Track confirm delays up to 25 blocks, can't estimate beyond that */
static const unsigned int MAX_BLOCK_CONFIRMS = 25;
/** Decay of .998 is a half-life of 346 blocks or about 2.4 days */
static const double DEFAULT_DECAY = .998;
-/** Require greater than 95% of X fee transactions to be confirmed within Y blocks for X to be big enough */
+/** 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;
-static const double UNLIKELY_PCT = .5;
-/** Require an avg of 1 tx in the combined fee bucket per block to have stat significance */
+/** Require an avg of 1 tx in the combined feerate bucket per block to have stat significance */
static const double SUFFICIENT_FEETXS = 1;
-/** Require only an avg of 1 tx every 5 blocks in the combined pri bucket (way less pri txs) */
-static const double SUFFICIENT_PRITXS = .2;
-
-// Minimum and Maximum values for tracking fees and priorities
-static const double MIN_FEERATE = 10;
-static const double MAX_FEERATE = 1e7;
+// 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 const double MAX_BUCKET_FEERATE = 1e7;
static const double INF_FEERATE = MAX_MONEY;
-static const double MIN_PRIORITY = 10;
-static const double MAX_PRIORITY = 1e16;
-static const double INF_PRIORITY = 1e9 * MAX_MONEY;
-// We have to lump transactions into buckets based on fee or priority, but we want to be able
-// to give accurate estimates over a large range of potential fees and priorities
+// 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;
-/** Spacing of Priority buckets */
-static const double PRI_SPACING = 2;
-
/**
- * We want to be able to estimate fees or priorities that are needed on tx's to be included in
+ * We want to be able to estimate feerates that are needed on tx's to be included in
* a certain number of blocks. Every time a block is added to the best chain, this class records
* stats on the transactions included in that block
*/
@@ -219,72 +99,58 @@ class CBlockPolicyEstimator
{
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<CTxMemPoolEntry>& entries, bool fCurrentEstimate);
-
- /** Process a transaction confirmed in a block*/
- void processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry);
+ std::vector<const CTxMemPoolEntry*>& entries);
/** Process a transaction accepted to the mempool*/
- void processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate);
+ void processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate);
/** Remove a transaction from the mempool tracking stats*/
- void removeTx(uint256 hash);
+ bool removeTx(uint256 hash);
- /** Is this transaction likely included in a block because of its fee?*/
- bool isFeeDataPoint(const CFeeRate &fee, double pri);
+ /** Return a feerate estimate */
+ CFeeRate estimateFee(int confTarget) const;
- /** Is this transaction likely included in a block because of its priority?*/
- bool isPriDataPoint(const CFeeRate &fee, double pri);
-
- /** Return a fee estimate */
- CFeeRate estimateFee(int confTarget);
-
- /** Estimate fee rate needed to get be included in a block within
+ /** 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.
*/
- CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
-
- /** Return a priority estimate */
- double estimatePriority(int confTarget);
-
- /** Estimate priority 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.
- */
- double estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
+ CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool) 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);
+ bool Read(CAutoFile& filein);
private:
CFeeRate minTrackedFee; //!< Passed to constructor to avoid dependency on main
- double minTrackedPriority; //!< Set to AllowFreeThreshold
unsigned int nBestSeenHeight;
struct TxStatsInfo
{
- TxConfirmStats *stats;
unsigned int blockHeight;
unsigned int bucketIndex;
- TxStatsInfo() : stats(NULL), blockHeight(0), bucketIndex(0) {}
+ TxStatsInfo() : blockHeight(0), bucketIndex(0) {}
};
// map of txids to information about that transaction
std::map<uint256, TxStatsInfo> mapMemPoolTxs;
/** Classes to track historical data on transaction confirmations */
- TxConfirmStats feeStats, priStats;
+ TxConfirmStats* feeStats;
+
+ unsigned int trackedTxs;
+ unsigned int untrackedTxs;
+
+ mutable CCriticalSection cs_feeEstimator;
+
+ /** Process a transaction confirmed in a block*/
+ bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry);
- /** Breakpoints to help determine whether a transaction was confirmed by priority or Fee */
- CFeeRate feeLikely, feeUnlikely;
- double priLikely, priUnlikely;
};
class FeeFilterRounder
@@ -298,5 +164,6 @@ public:
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 f2148bfe10..2b19a6714b 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin developers
+// 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.
@@ -7,13 +7,51 @@
#include "policy/policy.h"
-#include "main.h"
+#include "validation.h"
+#include "coins.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
#include <boost/foreach.hpp>
+CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee)
+{
+ // "Dust" is defined in terms of dustRelayFee,
+ // 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*dustRelayFee/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*dustRelayFee/1000 (in satoshis).
+ 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 3 * dustRelayFee.GetFee(nSize);
+}
+
+bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee)
+{
+ return (txout.nValue < GetDustThreshold(txout, dustRelayFee));
+}
+
/**
* Check transaction inputs to mitigate two
* potential denial-of-service attacks:
@@ -31,7 +69,7 @@
* DUP CHECKSIG DROP ... repeated 100 times... OP_1
*/
-bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
+bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled)
{
std::vector<std::vector<unsigned char> > vSolutions;
if (!Solver(scriptPubKey, whichType, vSolutions))
@@ -50,10 +88,13 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
(!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes))
return false;
+ else if (!witnessEnabled && (whichType == TX_WITNESS_V0_KEYHASH || whichType == TX_WITNESS_V0_SCRIPTHASH))
+ return false;
+
return whichType != TX_NONSTANDARD;
}
-bool IsStandardTx(const CTransaction& tx, std::string& reason)
+bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled)
{
if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) {
reason = "version";
@@ -63,9 +104,9 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason)
// Extremely large transactions with lots of inputs can cost the network
// almost as much to process as they cost the sender in fees, because
// computing signature hashes is O(ninputs*txsize). Limiting transactions
- // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
- unsigned int sz = GetTransactionCost(tx);
- if (sz >= MAX_STANDARD_TX_COST) {
+ // to MAX_STANDARD_TX_WEIGHT mitigates CPU exhaustion attacks.
+ unsigned int sz = GetTransactionWeight(tx);
+ if (sz >= MAX_STANDARD_TX_WEIGHT) {
reason = "tx-size";
return false;
}
@@ -92,7 +133,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason)
unsigned int nDataOut = 0;
txnouttype whichType;
BOOST_FOREACH(const CTxOut& txout, tx.vout) {
- if (!::IsStandard(txout.scriptPubKey, whichType)) {
+ if (!::IsStandard(txout.scriptPubKey, whichType, witnessEnabled)) {
reason = "scriptpubkey";
return false;
}
@@ -102,7 +143,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason)
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
reason = "bare-multisig";
return false;
- } else if (txout.IsDust(::minRelayTxFee)) {
+ } else if (IsDust(txout, ::dustRelayFee)) {
reason = "dust";
return false;
}
@@ -151,12 +192,68 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
return true;
}
-int64_t GetVirtualTransactionSize(int64_t nCost)
+bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
+{
+ if (tx.IsCoinBase())
+ return true; // Coinbases are skipped
+
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ // We don't care if witness for this input is empty, since it must not be bloated.
+ // If the script is invalid without witness, it would be caught sooner or later during validation.
+ if (tx.vin[i].scriptWitness.IsNull())
+ continue;
+
+ const CTxOut &prev = mapInputs.GetOutputFor(tx.vin[i]);
+
+ // get the scriptPubKey corresponding to this input:
+ CScript prevScript = prev.scriptPubKey;
+
+ if (prevScript.IsPayToScriptHash()) {
+ std::vector <std::vector<unsigned char> > stack;
+ // If the scriptPubKey is P2SH, we try to extract the redeemScript casually by converting the scriptSig
+ // into a stack. We do not check IsPushOnly nor compare the hash as these will be done later anyway.
+ // If the check fails at this stage, we know that this txid must be a bad one.
+ if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE))
+ return false;
+ if (stack.empty())
+ return false;
+ prevScript = CScript(stack.back().begin(), stack.back().end());
+ }
+
+ int witnessversion = 0;
+ std::vector<unsigned char> witnessprogram;
+
+ // Non-witness program must not be associated with any witness
+ if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram))
+ return false;
+
+ // Check P2WSH standard limits
+ if (witnessversion == 0 && witnessprogram.size() == 32) {
+ if (tx.vin[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
+ return false;
+ size_t sizeWitnessStack = tx.vin[i].scriptWitness.stack.size() - 1;
+ if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
+ return false;
+ for (unsigned int j = 0; j < sizeWitnessStack; j++) {
+ if (tx.vin[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
+CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
+unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
+
+int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)
{
- return (nCost + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
+ return (std::max(nWeight, nSigOpCost * nBytesPerSigOp) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
}
-int64_t GetVirtualTransactionSize(const CTransaction& tx)
+int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost)
{
- return GetVirtualTransactionSize(GetTransactionCost(tx));
+ return GetVirtualTransactionSize(GetTransactionWeight(tx), nSigOpCost);
}
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 29a8cc57c2..2c2ea9d5b8 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin developers
+// 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.
@@ -7,27 +7,45 @@
#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 -blockmaxcost, which control the range of block costs the mining code will create **/
-static const unsigned int DEFAULT_BLOCK_MAX_COST = 3000000;
-/** The maximum size for transactions we're willing to relay/mine */
-static const unsigned int MAX_STANDARD_TX_COST = 400000;
+/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
+static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000;
+/** 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 */
+static const unsigned int MAX_STANDARD_TX_WEIGHT = 400000;
/** Maximum number of signature check operations in an IsStandard() P2SH script */
static const unsigned int MAX_P2SH_SIGOPS = 15;
/** The maximum number of sigops we're willing to relay/mine in a single tx */
static const unsigned int MAX_STANDARD_TX_SIGOPS_COST = MAX_BLOCK_SIGOPS_COST/5;
/** Default for -maxmempool, maximum megabytes of mempool memory usage */
static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
+/** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or BIP 125 replacement **/
+static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000;
+/** Default for -bytespersigop */
+static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
+/** The maximum number of witness stack items in a standard P2WSH script */
+static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
+/** The maximum size of each witness stack item in a standard P2WSH script */
+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
+ * 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;
/**
* Standard script verification flags that standard transactions will comply
* with. However scripts violating these flags may still be present in valid
@@ -40,11 +58,14 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
SCRIPT_VERIFY_NULLDUMMY |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
SCRIPT_VERIFY_CLEANSTACK |
+ SCRIPT_VERIFY_MINIMALIF |
+ SCRIPT_VERIFY_NULLFAIL |
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
SCRIPT_VERIFY_LOW_S |
SCRIPT_VERIFY_WITNESS |
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM;
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
+ SCRIPT_VERIFY_WITNESS_PUBKEYTYPE;
/** For convenience, standard but not mandatory verify flags. */
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
@@ -53,21 +74,35 @@ 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;
-bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
+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
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
*/
-bool IsStandardTx(const CTransaction& tx, std::string& reason);
+bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled = false);
/**
* Check for standard transaction types
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
* @return True if all inputs (scriptSigs) use only standard transaction forms
*/
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
+ /**
+ * Check if the transaction is over standard P2WSH resources limit:
+ * 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements
+ * These limits are adequate for multi-signature up to n-of-100 using OP_CHECKSIG, OP_ADD, and OP_EQUAL,
+ */
+bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
+
+extern CFeeRate incrementalRelayFee;
+extern CFeeRate dustRelayFee;
+extern unsigned int nBytesPerSigOp;
-/** Compute the virtual transaction size (cost reinterpreted as bytes). */
-int64_t GetVirtualTransactionSize(int64_t nCost);
-int64_t GetVirtualTransactionSize(const CTransaction& tx);
+/** Compute the virtual transaction size (weight reinterpreted as bytes). */
+int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost);
+int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost = 0);
#endif // BITCOIN_POLICY_POLICY_H
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 133cff611d..d9b47e71bb 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 The Bitcoin developers
+// Copyright (c) 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.
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
index 5a711dba07..139aec5760 100644
--- a/src/policy/rbf.h
+++ b/src/policy/rbf.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 The Bitcoin developers
+// Copyright (c) 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.
diff --git a/src/pow.cpp b/src/pow.cpp
index 1db3b69293..e06d9662e6 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -12,12 +12,9 @@
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
+ assert(pindexLast != NULL);
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/pow.h b/src/pow.h
index 23e9c1c351..e203f492a1 100644
--- a/src/pow.h
+++ b/src/pow.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
diff --git a/src/prevector.h b/src/prevector.h
index a0e1e140b4..177d81383e 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -1,15 +1,17 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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_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
@@ -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));
@@ -248,6 +255,10 @@ public:
}
}
+ prevector(prevector<N, T, Size, Diff>&& other) : _size(0) {
+ swap(other);
+ }
+
prevector& operator=(const prevector<N, T, Size, Diff>& other) {
if (&other == this) {
return *this;
@@ -263,6 +274,11 @@ public:
return *this;
}
+ prevector& operator=(prevector<N, T, Size, Diff>&& other) {
+ swap(other);
+ return *this;
+ }
+
size_type size() const {
return is_direct() ? _size : _size - N - 1;
}
@@ -373,10 +389,14 @@ public:
iterator erase(iterator first, iterator last) {
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;
@@ -417,7 +437,9 @@ public:
}
~prevector() {
- clear();
+ if (!std::is_trivially_destructible<T>::value) {
+ clear();
+ }
if (!is_direct()) {
free(_union.indirect);
_union.indirect = NULL;
@@ -475,6 +497,14 @@ public:
return ((size_t)(sizeof(T))) * _union.capacity;
}
}
+
+ value_type* data() {
+ return item_ptr(0);
+ }
+
+ const value_type* data() const {
+ return item_ptr(0);
+ }
};
#pragma pack(pop)
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index df900388f2..9a979094cc 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -27,16 +27,16 @@ std::string CBlock::ToString() const
vtx.size());
for (unsigned int i = 0; i < vtx.size(); i++)
{
- s << " " << vtx[i].ToString() << "\n";
+ s << " " << vtx[i]->ToString() << "\n";
}
return s.str();
}
-int64_t GetBlockCost(const CBlock& block)
+int64_t GetBlockWeight(const CBlock& block)
{
- // This implements the cost = (stripped_size * 4) + witness_size formula,
+ // 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:
- // cost = (stripped_size * 3) + total_size.
+ // 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 e2a309e63d..4c6eb20ad5 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -36,7 +36,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(this->nVersion);
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
@@ -73,7 +73,7 @@ class CBlock : public CBlockHeader
{
public:
// network and disk
- std::vector<CTransaction> vtx;
+ std::vector<CTransactionRef> vtx;
// memory only
mutable bool fChecked;
@@ -92,7 +92,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CBlockHeader*)this);
READWRITE(vtx);
}
@@ -137,8 +137,9 @@ struct CBlockLocator
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ int nVersion = s.GetVersion();
+ if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vHave);
}
@@ -154,7 +155,7 @@ struct CBlockLocator
}
};
-/** Compute the consensus-critical block cost (see BIP 141). */
-int64_t GetBlockCost(const CBlock& tx);
+/** 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 7f10409c05..a0d7793f97 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -49,49 +49,36 @@ CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
scriptPubKey = scriptPubKeyIn;
}
-uint256 CTxOut::GetHash() const
-{
- return SerializeHash(*this);
-}
-
std::string CTxOut::ToString() const
{
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
}
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
-CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), wit(tx.wit), nLockTime(tx.nLockTime) {}
+CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
uint256 CMutableTransaction::GetHash() const
{
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
}
-void CTransaction::UpdateHash() const
+uint256 CTransaction::ComputeHash() const
{
- *const_cast<uint256*>(&hash) = SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
+ return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
}
uint256 CTransaction::GetWitnessHash() const
{
+ if (!HasWitness()) {
+ return GetHash();
+ }
return SerializeHash(*this, SER_GETHASH, 0);
}
-CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0) { }
-
-CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), wit(tx.wit), nLockTime(tx.nLockTime) {
- UpdateHash();
-}
-
-CTransaction& CTransaction::operator=(const CTransaction &tx) {
- *const_cast<int*>(&nVersion) = tx.nVersion;
- *const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
- *const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
- *const_cast<CTxWitness*>(&wit) = tx.wit;
- *const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
- *const_cast<uint256*>(&hash) = tx.hash;
- return *this;
-}
+/* 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()) {}
CAmount CTransaction::GetValueOut() const
{
@@ -100,35 +87,14 @@ CAmount CTransaction::GetValueOut() const
{
nValueOut += it->nValue;
if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))
- throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
+ 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
+unsigned int CTransaction::GetTotalSize() 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 = (GetTransactionCost(*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;
+ return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
}
std::string CTransaction::ToString() const
@@ -142,14 +108,14 @@ std::string CTransaction::ToString() const
nLockTime);
for (unsigned int i = 0; i < vin.size(); i++)
str += " " + vin[i].ToString() + "\n";
- for (unsigned int i = 0; i < wit.vtxinwit.size(); i++)
- str += " " + wit.vtxinwit[i].scriptWitness.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";
return str;
}
-int64_t GetTransactionCost(const CTransaction& tx)
+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 8a2d5dd22c..00ac0b92b5 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -22,13 +22,13 @@ 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;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(hash);
READWRITE(n);
}
@@ -65,6 +65,7 @@ public:
COutPoint prevout;
CScript scriptSig;
uint32_t nSequence;
+ CScriptWitness scriptWitness; //! Only serialized through CTransaction
/* Setting nSequence to this value for every input in a transaction
* disables nLockTime. */
@@ -104,7 +105,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(prevout);
READWRITE(*(CScriptBase*)(&scriptSig));
READWRITE(nSequence);
@@ -144,7 +145,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nValue);
READWRITE(*(CScriptBase*)(&scriptPubKey));
}
@@ -160,45 +161,6 @@ public:
return (nValue == -1);
}
- uint256 GetHash() const;
-
- 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(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 &&
@@ -213,62 +175,6 @@ public:
std::string ToString() const;
};
-class CTxInWitness
-{
-public:
- CScriptWitness scriptWitness;
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
- {
- READWRITE(scriptWitness.stack);
- }
-
- bool IsNull() const { return scriptWitness.IsNull(); }
-
- CTxInWitness() { }
-};
-
-class CTxWitness
-{
-public:
- /** In case vtxinwit is missing, all entries are treated as if they were empty CTxInWitnesses */
- std::vector<CTxInWitness> vtxinwit;
-
- ADD_SERIALIZE_METHODS;
-
- bool IsEmpty() const { return vtxinwit.empty(); }
-
- bool IsNull() const
- {
- for (size_t n = 0; n < vtxinwit.size(); n++) {
- if (!vtxinwit[n].IsNull()) {
- return false;
- }
- }
- return true;
- }
-
- void SetNull()
- {
- vtxinwit.clear();
- }
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
- {
- for (size_t n = 0; n < vtxinwit.size(); n++) {
- READWRITE(vtxinwit[n]);
- }
- if (IsNull()) {
- /* It's illegal to encode a witness when all vtxinwit entries are empty. */
- throw std::ios_base::failure("Superfluous witness record");
- }
- }
-};
-
struct CMutableTransaction;
/**
@@ -288,74 +194,79 @@ struct CMutableTransaction;
* - CTxWitness wit;
* - uint32_t nLockTime
*/
-template<typename Stream, typename Operation, typename TxType>
-inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(*const_cast<int32_t*>(&tx.nVersion));
+template<typename Stream, typename TxType>
+inline void UnserializeTransaction(TxType& tx, Stream& s) {
+ const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
+
+ s >> tx.nVersion;
unsigned char flags = 0;
- if (ser_action.ForRead()) {
- const_cast<std::vector<CTxIn>*>(&tx.vin)->clear();
- const_cast<std::vector<CTxOut>*>(&tx.vout)->clear();
- const_cast<CTxWitness*>(&tx.wit)->SetNull();
- /* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */
- READWRITE(*const_cast<std::vector<CTxIn>*>(&tx.vin));
- if (tx.vin.size() == 0 && !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) {
- /* We read a dummy or an empty vin. */
- READWRITE(flags);
- if (flags != 0) {
- READWRITE(*const_cast<std::vector<CTxIn>*>(&tx.vin));
- READWRITE(*const_cast<std::vector<CTxOut>*>(&tx.vout));
- }
- } else {
- /* We read a non-empty vin. Assume a normal vout follows. */
- READWRITE(*const_cast<std::vector<CTxOut>*>(&tx.vout));
- }
- if ((flags & 1) && !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) {
- /* The witness flag is present, and we support witnesses. */
- flags ^= 1;
- const_cast<CTxWitness*>(&tx.wit)->vtxinwit.resize(tx.vin.size());
- READWRITE(tx.wit);
- }
- if (flags) {
- /* Unknown flag in the serialization */
- throw std::ios_base::failure("Unknown transaction optional data");
+ tx.vin.clear();
+ tx.vout.clear();
+ /* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */
+ s >> tx.vin;
+ if (tx.vin.size() == 0 && fAllowWitness) {
+ /* We read a dummy or an empty vin. */
+ s >> flags;
+ if (flags != 0) {
+ s >> tx.vin;
+ s >> tx.vout;
}
} else {
- // Consistency check
- assert(tx.wit.vtxinwit.size() <= tx.vin.size());
- if (!(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) {
- /* Check whether witnesses need to be serialized. */
- if (!tx.wit.IsNull()) {
- flags |= 1;
- }
+ /* We read a non-empty vin. Assume a normal vout follows. */
+ s >> tx.vout;
+ }
+ if ((flags & 1) && fAllowWitness) {
+ /* The witness flag is present, and we support witnesses. */
+ flags ^= 1;
+ for (size_t i = 0; i < tx.vin.size(); i++) {
+ s >> tx.vin[i].scriptWitness.stack;
}
- if (flags) {
- /* Use extended format in case witnesses are to be serialized. */
- std::vector<CTxIn> vinDummy;
- READWRITE(vinDummy);
- READWRITE(flags);
+ }
+ if (flags) {
+ /* Unknown flag in the serialization */
+ throw std::ios_base::failure("Unknown transaction optional data");
+ }
+ s >> tx.nLockTime;
+}
+
+template<typename Stream, typename TxType>
+inline void SerializeTransaction(const TxType& tx, Stream& s) {
+ const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
+
+ s << tx.nVersion;
+ unsigned char flags = 0;
+ // Consistency check
+ if (fAllowWitness) {
+ /* Check whether witnesses need to be serialized. */
+ if (tx.HasWitness()) {
+ flags |= 1;
}
- READWRITE(*const_cast<std::vector<CTxIn>*>(&tx.vin));
- READWRITE(*const_cast<std::vector<CTxOut>*>(&tx.vout));
- if (flags & 1) {
- const_cast<CTxWitness*>(&tx.wit)->vtxinwit.resize(tx.vin.size());
- READWRITE(tx.wit);
+ }
+ if (flags) {
+ /* Use extended format in case witnesses are to be serialized. */
+ std::vector<CTxIn> vinDummy;
+ s << vinDummy;
+ s << flags;
+ }
+ s << tx.vin;
+ s << tx.vout;
+ if (flags & 1) {
+ for (size_t i = 0; i < tx.vin.size(); i++) {
+ s << tx.vin[i].scriptWitness.stack;
}
}
- READWRITE(*const_cast<uint32_t*>(&tx.nLockTime));
+ s << tx.nLockTime;
}
+
/** The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs.
*/
class CTransaction
{
-private:
- /** Memory only. */
- const uint256 hash;
-
public:
// Default transaction version.
- static const int32_t CURRENT_VERSION=1;
+ static const int32_t CURRENT_VERSION=2;
// Changing the default transaction version requires a two step process: first
// adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date
@@ -371,27 +282,32 @@ public:
const int32_t nVersion;
const std::vector<CTxIn> vin;
const std::vector<CTxOut> vout;
- CTxWitness wit; // Not const: can change without invalidating the txid cache
const uint32_t nLockTime;
+private:
+ /** Memory only. */
+ const uint256 hash;
+
+ uint256 ComputeHash() const;
+
+public:
/** Construct a CTransaction that qualifies as IsNull() */
CTransaction();
/** Convert a CMutableTransaction into a CTransaction. */
CTransaction(const CMutableTransaction &tx);
+ CTransaction(CMutableTransaction &&tx);
- CTransaction& operator=(const CTransaction& tx);
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- SerializeTransaction(*this, s, ser_action, nType, nVersion);
- if (ser_action.ForRead()) {
- UpdateHash();
- }
+ template <typename Stream>
+ inline void Serialize(Stream& s) const {
+ SerializeTransaction(*this, s);
}
+ /** This deserializing constructor is provided instead of an Unserialize method.
+ * Unserialize is not possible, since it would require overwriting const fields. */
+ template <typename Stream>
+ CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {}
+
bool IsNull() const {
return vin.empty() && vout.empty();
}
@@ -408,11 +324,12 @@ 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.
+ * @return Total transaction size in bytes
+ */
+ unsigned int GetTotalSize() const;
bool IsCoinBase() const
{
@@ -431,7 +348,15 @@ public:
std::string ToString() const;
- void UpdateHash() const;
+ bool HasWitness() const
+ {
+ for (size_t i = 0; i < vin.size(); i++) {
+ if (!vin[i].scriptWitness.IsNull()) {
+ return true;
+ }
+ }
+ return false;
+ }
};
/** A mutable version of CTransaction. */
@@ -440,26 +365,53 @@ struct CMutableTransaction
int32_t nVersion;
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
- CTxWitness wit;
uint32_t nLockTime;
CMutableTransaction();
CMutableTransaction(const CTransaction& tx);
- ADD_SERIALIZE_METHODS;
+ template <typename Stream>
+ inline void Serialize(Stream& s) const {
+ SerializeTransaction(*this, s);
+ }
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- SerializeTransaction(*this, s, ser_action, nType, nVersion);
+
+ template <typename Stream>
+ inline void Unserialize(Stream& s) {
+ UnserializeTransaction(*this, s);
+ }
+
+ template <typename Stream>
+ CMutableTransaction(deserialize_type, Stream& s) {
+ Unserialize(s);
}
/** Compute the hash of this CMutableTransaction. This is computed on the
* fly, as opposed to GetHash() in CTransaction, which uses a cached result.
*/
uint256 GetHash() const;
+
+ friend bool operator==(const CMutableTransaction& a, const CMutableTransaction& b)
+ {
+ return a.GetHash() == b.GetHash();
+ }
+
+ bool HasWitness() const
+ {
+ for (size_t i = 0; i < vin.size(); i++) {
+ if (!vin[i].scriptWitness.IsNull()) {
+ return true;
+ }
+ }
+ return false;
+ }
};
-/** Compute the cost of a transaction, as defined by BIP 141 */
-int64_t GetTransactionCost(const CTransaction &tx);
+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 247c6c2120..28d1d0eeb4 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -79,7 +79,7 @@ CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn)
memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE);
memset(pchCommand, 0, sizeof(pchCommand));
nMessageSize = -1;
- nChecksum = 0;
+ memset(pchChecksum, 0, CHECKSUM_SIZE);
}
CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn)
@@ -88,7 +88,7 @@ CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn, const
memset(pchCommand, 0, sizeof(pchCommand));
strncpy(pchCommand, pszCommand, COMMAND_SIZE);
nMessageSize = nMessageSizeIn;
- nChecksum = 0;
+ memset(pchChecksum, 0, CHECKSUM_SIZE);
}
std::string CMessageHeader::GetCommand() const
@@ -181,7 +181,11 @@ std::string CInv::GetCommand() const
std::string CInv::ToString() const
{
- return strprintf("%s %s", GetCommand(), hash.ToString());
+ try {
+ return strprintf("%s %s", GetCommand(), hash.ToString());
+ } catch(const std::out_of_range &) {
+ return strprintf("0x%08x %s", type, hash.ToString());
+ }
}
const std::vector<std::string> &getAllNetMessageTypes()
diff --git a/src/protocol.h b/src/protocol.h
index 15f27e2d2f..eba39ab1e5 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -10,7 +10,7 @@
#ifndef BITCOIN_PROTOCOL_H
#define BITCOIN_PROTOCOL_H
-#include "netbase.h"
+#include "netaddress.h"
#include "serialize.h"
#include "uint256.h"
#include "version.h"
@@ -18,8 +18,6 @@
#include <stdint.h>
#include <string>
-#define MESSAGE_START_SIZE 4
-
/** Message header.
* (4) message start.
* (12) command.
@@ -29,6 +27,16 @@
class CMessageHeader
{
public:
+ enum {
+ MESSAGE_START_SIZE = 4,
+ COMMAND_SIZE = 12,
+ MESSAGE_SIZE_SIZE = 4,
+ CHECKSUM_SIZE = 4,
+
+ MESSAGE_SIZE_OFFSET = MESSAGE_START_SIZE + COMMAND_SIZE,
+ CHECKSUM_OFFSET = MESSAGE_SIZE_OFFSET + MESSAGE_SIZE_SIZE,
+ HEADER_SIZE = MESSAGE_START_SIZE + COMMAND_SIZE + MESSAGE_SIZE_SIZE + CHECKSUM_SIZE
+ };
typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];
CMessageHeader(const MessageStartChars& pchMessageStartIn);
@@ -40,29 +48,18 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
+ inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(FLATDATA(pchMessageStart));
READWRITE(FLATDATA(pchCommand));
READWRITE(nMessageSize);
- READWRITE(nChecksum);
+ READWRITE(FLATDATA(pchChecksum));
}
- // TODO: make private (improves encapsulation)
-public:
- enum {
- COMMAND_SIZE = 12,
- MESSAGE_SIZE_SIZE = sizeof(int),
- CHECKSUM_SIZE = sizeof(int),
-
- MESSAGE_SIZE_OFFSET = MESSAGE_START_SIZE + COMMAND_SIZE,
- CHECKSUM_OFFSET = MESSAGE_SIZE_OFFSET + MESSAGE_SIZE_SIZE,
- HEADER_SIZE = MESSAGE_START_SIZE + COMMAND_SIZE + MESSAGE_SIZE_SIZE + CHECKSUM_SIZE
- };
char pchMessageStart[MESSAGE_START_SIZE];
char pchCommand[COMMAND_SIZE];
- unsigned int nMessageSize;
- unsigned int nChecksum;
+ uint32_t nMessageSize;
+ uint8_t pchChecksum[CHECKSUM_SIZE];
};
/**
@@ -264,9 +261,12 @@ enum ServiceFlags : uint64_t {
// Bitcoin Core nodes used to support this by default, without advertising this bit,
// but no longer do as of protocol version 70011 (= NO_BLOOM_VERSION)
NODE_BLOOM = (1 << 2),
- // Indicates that a node can be asked for blocks and transactions including
+ // NODE_WITNESS indicates that a node can be asked for blocks and transactions including
// witness data.
NODE_WITNESS = (1 << 3),
+ // NODE_XTHIN means the node supports Xtreme Thinblocks
+ // If this is turned off then the node will not service nor make xthin requests
+ NODE_XTHIN = (1 << 4),
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the
@@ -289,14 +289,15 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
+ inline void SerializationOp(Stream& s, Operation ser_action)
{
if (ser_action.ForRead())
Init();
- if (nType & SER_DISK)
+ int nVersion = s.GetVersion();
+ if (s.GetType() & SER_DISK)
READWRITE(nVersion);
- if ((nType & SER_DISK) ||
- (nVersion >= CADDR_TIME_VERSION && !(nType & SER_GETHASH)))
+ if ((s.GetType() & SER_DISK) ||
+ (nVersion >= CADDR_TIME_VERSION && !(s.GetType() & SER_GETHASH)))
READWRITE(nTime);
uint64_t nServicesInt = nServices;
READWRITE(nServicesInt);
@@ -312,20 +313,24 @@ public:
unsigned int nTime;
};
-/** getdata message types */
+/** getdata message type flags */
const uint32_t MSG_WITNESS_FLAG = 1 << 30;
const uint32_t MSG_TYPE_MASK = 0xffffffff >> 2;
+
+/** getdata / inv message types.
+ * These numbers are defined by the protocol. When adding a new value, be sure
+ * to mention it in the respective BIP.
+ */
enum GetDataMsg
{
UNDEFINED = 0,
- MSG_TX,
- MSG_BLOCK,
- MSG_TYPE_MAX = MSG_BLOCK,
+ MSG_TX = 1,
+ MSG_BLOCK = 2,
// The following can only occur in getdata. Invs always use TX or BLOCK.
- MSG_FILTERED_BLOCK,
- MSG_CMPCT_BLOCK,
- MSG_WITNESS_BLOCK = MSG_BLOCK | MSG_WITNESS_FLAG,
- MSG_WITNESS_TX = MSG_TX | MSG_WITNESS_FLAG,
+ MSG_FILTERED_BLOCK = 3, //!< Defined in BIP37
+ MSG_CMPCT_BLOCK = 4, //!< Defined in BIP152
+ MSG_WITNESS_BLOCK = MSG_BLOCK | MSG_WITNESS_FLAG, //!< Defined in BIP144
+ MSG_WITNESS_TX = MSG_TX | MSG_WITNESS_FLAG, //!< Defined in BIP144
MSG_FILTERED_WITNESS_BLOCK = MSG_FILTERED_BLOCK | MSG_WITNESS_FLAG,
};
@@ -339,7 +344,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
+ inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(type);
READWRITE(hash);
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index be4ee27cd4..e57fa238cb 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -264,12 +264,12 @@ void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {
pubkey.Set(code+41, code+BIP32_EXTKEY_SIZE);
}
-bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const {
+bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
out.nDepth = nDepth + 1;
CKeyID id = pubkey.GetID();
memcpy(&out.vchFingerprint[0], &id, 4);
- out.nChild = nChild;
- return pubkey.Derive(out.pubkey, out.chaincode, nChild, chaincode);
+ out.nChild = _nChild;
+ return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode);
}
/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
diff --git a/src/pubkey.h b/src/pubkey.h
index db5444ea9d..dbf0e23f20 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -13,7 +13,7 @@
#include <stdexcept>
#include <vector>
-/**
+/**
* secp256k1:
* const unsigned int PRIVATE_KEY_SIZE = 279;
* const unsigned int PUBLIC_KEY_SIZE = 65;
@@ -88,9 +88,9 @@ public:
}
//! Construct a public key from a byte vector.
- CPubKey(const std::vector<unsigned char>& vch)
+ CPubKey(const std::vector<unsigned char>& _vch)
{
- Set(vch.begin(), vch.end());
+ Set(_vch.begin(), _vch.end());
}
//! Simple read-only vector-like interface to the pubkey data.
@@ -116,19 +116,15 @@ public:
}
//! Implement serialization, as if this was a byte vector.
- unsigned int GetSerializeSize(int nType, int nVersion) const
- {
- return size() + 1;
- }
template <typename Stream>
- void Serialize(Stream& s, int nType, int nVersion) const
+ void Serialize(Stream& s) const
{
unsigned int len = size();
::WriteCompactSize(s, len);
s.write((char*)vch, len);
}
template <typename Stream>
- void Unserialize(Stream& s, int nType, int nVersion)
+ void Unserialize(Stream& s)
{
unsigned int len = ::ReadCompactSize(s);
if (len <= 65) {
@@ -156,7 +152,7 @@ public:
/*
* Check syntactic correctness.
- *
+ *
* Note that this is consensus critical as CheckSig() calls it!
*/
bool IsValid() const
@@ -203,20 +199,24 @@ struct CExtPubKey {
friend bool operator==(const CExtPubKey &a, const CExtPubKey &b)
{
- return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild &&
- a.chaincode == b.chaincode && a.pubkey == b.pubkey;
+ return a.nDepth == b.nDepth &&
+ memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 &&
+ a.nChild == b.nChild &&
+ a.chaincode == b.chaincode &&
+ a.pubkey == b.pubkey;
}
void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
bool Derive(CExtPubKey& out, unsigned int nChild) const;
- unsigned int GetSerializeSize(int nType, int nVersion) const
+ void Serialize(CSizeComputer& s) const
{
- return BIP32_EXTKEY_SIZE+1; //add one byte for the size (compact int)
+ // Optimized implementation for ::GetSerializeSize that avoids copying.
+ s.seek(BIP32_EXTKEY_SIZE + 1); // add one byte for the size (compact int)
}
template <typename Stream>
- void Serialize(Stream& s, int nType, int nVersion) const
+ void Serialize(Stream& s) const
{
unsigned int len = BIP32_EXTKEY_SIZE;
::WriteCompactSize(s, len);
@@ -225,7 +225,7 @@ struct CExtPubKey {
s.write((const char *)&code[0], len);
}
template <typename Stream>
- void Unserialize(Stream& s, int nType, int nVersion)
+ void Unserialize(Stream& s)
{
unsigned int len = ::ReadCompactSize(s);
unsigned char code[BIP32_EXTKEY_SIZE];
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 135f15ffa8..b1253a9f17 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -21,12 +21,12 @@
#include <QMessageBox>
#include <QSortFilterProxyModel>
-AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent) :
+AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) :
QDialog(parent),
ui(new Ui::AddressBookPage),
model(0),
- mode(mode),
- tab(tab)
+ mode(_mode),
+ tab(_tab)
{
ui->setupUi(this);
@@ -83,7 +83,7 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode,
deleteAction = new QAction(ui->deleteAddress->text(), this);
// Build context menu
- contextMenu = new QMenu();
+ contextMenu = new QMenu(this);
contextMenu->addAction(copyAddressAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(editAction);
@@ -107,14 +107,14 @@ AddressBookPage::~AddressBookPage()
delete ui;
}
-void AddressBookPage::setModel(AddressTableModel *model)
+void AddressBookPage::setModel(AddressTableModel *_model)
{
- this->model = model;
- if(!model)
+ this->model = _model;
+ if(!_model)
return;
proxyModel = new QSortFilterProxyModel(this);
- proxyModel->setSourceModel(model);
+ proxyModel->setSourceModel(_model);
proxyModel->setDynamicSortFilter(true);
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
@@ -147,7 +147,7 @@ void AddressBookPage::setModel(AddressTableModel *model)
this, SLOT(selectionChanged()));
// Select row for newly created address
- connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int)));
+ connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int)));
selectionChanged();
}
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 71ed3618e4..93120de1ea 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -31,8 +31,8 @@ struct AddressTableEntry
QString address;
AddressTableEntry() {}
- AddressTableEntry(Type type, const QString &label, const QString &address):
- type(type), label(label), address(address) {}
+ AddressTableEntry(Type _type, const QString &_label, const QString &_address):
+ type(_type), label(_label), address(_address) {}
};
struct AddressTableEntryLessThan
@@ -73,8 +73,8 @@ public:
QList<AddressTableEntry> cachedAddressTable;
AddressTableModel *parent;
- AddressTablePriv(CWallet *wallet, AddressTableModel *parent):
- wallet(wallet), parent(parent) {}
+ AddressTablePriv(CWallet *_wallet, AddressTableModel *_parent):
+ wallet(_wallet), parent(_parent) {}
void refreshAddressTable()
{
@@ -164,8 +164,8 @@ public:
}
};
-AddressTableModel::AddressTableModel(CWallet *wallet, WalletModel *parent) :
- QAbstractTableModel(parent),walletModel(parent),wallet(wallet),priv(0)
+AddressTableModel::AddressTableModel(CWallet *_wallet, WalletModel *parent) :
+ QAbstractTableModel(parent),walletModel(parent),wallet(_wallet),priv(0)
{
columns << tr("Label") << tr("Address");
priv = new AddressTablePriv(wallet, this);
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index e8aa79679c..e9f5c77a5b 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -18,10 +18,10 @@
#include <QMessageBox>
#include <QPushButton>
-AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
+AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) :
QDialog(parent),
ui(new Ui::AskPassphraseDialog),
- mode(mode),
+ mode(_mode),
model(0),
fCapsLock(false)
{
@@ -81,9 +81,9 @@ AskPassphraseDialog::~AskPassphraseDialog()
delete ui;
}
-void AskPassphraseDialog::setModel(WalletModel *model)
+void AskPassphraseDialog::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
}
void AskPassphraseDialog::accept()
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index d95106b5ac..f8a99506c1 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -48,7 +48,8 @@ public:
void refreshBanlist()
{
banmap_t banMap;
- CNode::GetBanned(banMap);
+ if(g_connman)
+ g_connman->GetBanned(banMap);
cachedBanlist.clear();
#if QT_VERSION >= 0x040700
@@ -63,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));
}
@@ -86,7 +87,7 @@ BanTableModel::BanTableModel(ClientModel *parent) :
clientModel(parent)
{
columns << tr("IP/Netmask") << tr("Banned Until");
- priv = new BanTablePriv();
+ priv.reset(new BanTablePriv());
// default to unsorted
priv->sortColumn = -1;
@@ -94,6 +95,11 @@ BanTableModel::BanTableModel(ClientModel *parent) :
refresh();
}
+BanTableModel::~BanTableModel()
+{
+ // Intentionally left empty
+}
+
int BanTableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
@@ -175,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/bantablemodel.h b/src/qt/bantablemodel.h
index fe9600ac0b..062cfdc931 100644
--- a/src/qt/bantablemodel.h
+++ b/src/qt/bantablemodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -40,6 +40,7 @@ class BanTableModel : public QAbstractTableModel
public:
explicit BanTableModel(ClientModel *parent = 0);
+ ~BanTableModel();
void startAutoRefresh();
void stopAutoRefresh();
@@ -66,7 +67,7 @@ public Q_SLOTS:
private:
ClientModel *clientModel;
QStringList columns;
- BanTablePriv *priv;
+ std::unique_ptr<BanTablePriv> priv;
};
#endif // BITCOIN_QT_BANTABLEMODEL_H
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 64b5c83d72..23ec3ab434 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -10,6 +10,7 @@
#include "chainparams.h"
#include "clientmodel.h"
+#include "fs.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "intro.h"
@@ -30,6 +31,7 @@
#include "scheduler.h"
#include "ui_interface.h"
#include "util.h"
+#include "warnings.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
@@ -37,7 +39,6 @@
#include <stdint.h>
-#include <boost/filesystem/operations.hpp>
#include <boost/thread.hpp>
#include <QApplication>
@@ -151,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
@@ -177,8 +184,8 @@ public Q_SLOTS:
void shutdown();
Q_SIGNALS:
- void initializeResult(int retval);
- void shutdownResult(int retval);
+ void initializeResult(bool success);
+ void shutdownResult();
void runawayException(const QString &message);
private:
@@ -222,8 +229,8 @@ public:
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);
@@ -245,6 +252,7 @@ private:
#endif
int returnValue;
const PlatformStyle *platformStyle;
+ std::unique_ptr<QWidget> shutdownWindow;
void startThread();
};
@@ -259,15 +267,30 @@ BitcoinCore::BitcoinCore():
void BitcoinCore::handleRunawayException(const std::exception *e)
{
PrintExceptionContinue(e, "Runaway exception");
- Q_EMIT runawayException(QString::fromStdString(strMiscWarning));
+ Q_EMIT runawayException(QString::fromStdString(GetWarnings("gui")));
}
void BitcoinCore::initialize()
{
try
{
- qDebug() << __func__ << ": Running AppInit2 in thread";
- int rv = AppInit2(threadGroup, scheduler);
+ qDebug() << __func__ << ": Running initialization in thread";
+ if (!AppInitBasicSetup())
+ {
+ Q_EMIT initializeResult(false);
+ return;
+ }
+ if (!AppInitParameterInteraction())
+ {
+ Q_EMIT initializeResult(false);
+ return;
+ }
+ if (!AppInitSanityChecks())
+ {
+ Q_EMIT initializeResult(false);
+ return;
+ }
+ bool rv = AppInitMain(threadGroup, scheduler);
Q_EMIT initializeResult(rv);
} catch (const std::exception& e) {
handleRunawayException(&e);
@@ -285,7 +308,7 @@ 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 (...) {
@@ -365,9 +388,8 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
{
SplashScreen *splash = new SplashScreen(0, networkStyle);
- // We don't hold a direct pointer to the splash screen after creation, so use
- // Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually.
- splash->setAttribute(Qt::WA_DeleteOnClose);
+ // We don't hold a direct pointer to the splash screen after creation, but the splash
+ // screen will take care of deleting itself when slotFinish happens.
splash->show();
connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*)));
connect(this, SIGNAL(requestedShutdown()), splash, SLOT(close()));
@@ -382,8 +404,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()));
@@ -409,6 +431,11 @@ void BitcoinApplication::requestInitialize()
void BitcoinApplication::requestShutdown()
{
+ // Show a simple window indicating shutdown status
+ // Do this first as some of the steps may take some time below,
+ // for example the RPC console may still be executing a command.
+ shutdownWindow.reset(ShutdownWindow::showShutdownWindow(window));
+
qDebug() << __func__ << ": Requesting shutdown";
startThread();
window->hide();
@@ -423,21 +450,20 @@ void BitcoinApplication::requestShutdown()
delete clientModel;
clientModel = 0;
- // Show a simple window indicating shutdown status
- ShutdownWindow::showShutdownWindow(window);
+ StartShutdown();
// Request shutdown from core thread
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();
@@ -487,16 +513,15 @@ 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
}
void BitcoinApplication::handleRunawayException(const QString &message)
{
QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + message);
- ::exit(1);
+ ::exit(EXIT_FAILURE);
}
WId BitcoinApplication::getMainWinId() const
@@ -569,31 +594,32 @@ 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 (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version"))
+ if (IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version"))
{
- HelpMessageDialog help(NULL, mapArgs.count("-version"));
+ HelpMessageDialog help(NULL, IsArgSet("-version"));
help.showOrPrint();
- return 1;
+ return EXIT_SUCCESS;
}
/// 5. Now that settings and translations are available, ask user for data directory
// User language is set up: pick a data directory
- Intro::pickDataDirectory();
+ if (!Intro::pickDataDirectory())
+ return EXIT_SUCCESS;
/// 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(mapArgs["-datadir"])));
- return 1;
+ QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(GetArg("-datadir", ""))));
+ return EXIT_FAILURE;
}
try {
- ReadConfigFile(mapArgs, mapMultiArgs);
+ ReadConfigFile(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()));
- return false;
+ return EXIT_FAILURE;
}
/// 7. Determine network (and switch to network specific options)
@@ -607,7 +633,7 @@ int main(int argc, char *argv[])
SelectParams(ChainNameFromCommandLine());
} catch(std::exception &e) {
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what()));
- return 1;
+ return EXIT_FAILURE;
}
#ifdef ENABLE_WALLET
// Parse URIs on command line -- this can affect Params()
@@ -629,7 +655,7 @@ int main(int argc, char *argv[])
// - Do this after creating app and setting up translations, so errors are
// translated properly.
if (PaymentServer::ipcSendCommandLine())
- exit(0);
+ exit(EXIT_SUCCESS);
// Start up the payment server early, too, so impatient users that click on
// bitcoin: links repeatedly have their payment requests routed to this process:
@@ -653,7 +679,7 @@ int main(int argc, char *argv[])
// Allow parameter interaction before we create the options model
app.parameterSetup();
// Load GUI settings from QSettings
- app.createOptionsModel(mapArgs.count("-resetguisettings") != 0);
+ app.createOptionsModel(IsArgSet("-resetguisettings"));
// Subscribe to global signals from core
uiInterface.InitMessage.connect(InitMessage);
@@ -673,10 +699,10 @@ int main(int argc, char *argv[])
app.exec();
} catch (const std::exception& e) {
PrintExceptionContinue(&e, "Runaway exception");
- app.handleRunawayException(QString::fromStdString(strMiscWarning));
+ app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
} catch (...) {
PrintExceptionContinue(NULL, "Runaway exception");
- app.handleRunawayException(QString::fromStdString(strMiscWarning));
+ app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
}
return app.getReturnValue();
}
diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc
index 24b0bae3ec..451d391237 100644
--- a/src/qt/bitcoin.qrc
+++ b/src/qt/bitcoin.qrc
@@ -50,6 +50,9 @@
<file alias="fontsmaller">res/icons/fontsmaller.png</file>
<file alias="prompticon">res/icons/chevron.png</file>
<file alias="transaction_abandoned">res/icons/transaction_abandoned.png</file>
+ <file alias="hd_enabled">res/icons/hd_enabled.png</file>
+ <file alias="hd_disabled">res/icons/hd_disabled.png</file>
+ <file alias="network_disabled">res/icons/network_disabled.png</file>
</qresource>
<qresource prefix="/movies">
<file alias="spinner-000">res/movies/spinner-000.png</file>
diff --git a/src/qt/bitcoin_locale.qrc b/src/qt/bitcoin_locale.qrc
index 8dd07c3d41..f195b23d81 100644
--- a/src/qt/bitcoin_locale.qrc
+++ b/src/qt/bitcoin_locale.qrc
@@ -4,12 +4,11 @@
<file alias="af_ZA">locale/bitcoin_af_ZA.qm</file>
<file alias="ar">locale/bitcoin_ar.qm</file>
<file alias="be_BY">locale/bitcoin_be_BY.qm</file>
- <file alias="bg">locale/bitcoin_bg.qm</file>
<file alias="bg_BG">locale/bitcoin_bg_BG.qm</file>
+ <file alias="bg">locale/bitcoin_bg.qm</file>
<file alias="ca_ES">locale/bitcoin_ca_ES.qm</file>
<file alias="ca">locale/bitcoin_ca.qm</file>
<file alias="ca@valencia">locale/bitcoin_ca@valencia.qm</file>
- <file alias="cs_CZ">locale/bitcoin_cs_CZ.qm</file>
<file alias="cs">locale/bitcoin_cs.qm</file>
<file alias="cy">locale/bitcoin_cy.qm</file>
<file alias="da">locale/bitcoin_da.qm</file>
@@ -28,6 +27,7 @@
<file alias="es">locale/bitcoin_es.qm</file>
<file alias="es_UY">locale/bitcoin_es_UY.qm</file>
<file alias="es_VE">locale/bitcoin_es_VE.qm</file>
+ <file alias="et_EE">locale/bitcoin_et_EE.qm</file>
<file alias="et">locale/bitcoin_et.qm</file>
<file alias="eu_ES">locale/bitcoin_eu_ES.qm</file>
<file alias="fa_IR">locale/bitcoin_fa_IR.qm</file>
@@ -57,6 +57,7 @@
<file alias="mn">locale/bitcoin_mn.qm</file>
<file alias="ms_MY">locale/bitcoin_ms_MY.qm</file>
<file alias="nb">locale/bitcoin_nb.qm</file>
+ <file alias="ne">locale/bitcoin_ne.qm</file>
<file alias="nl">locale/bitcoin_nl.qm</file>
<file alias="pam">locale/bitcoin_pam.qm</file>
<file alias="pl">locale/bitcoin_pl.qm</file>
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 9042e3b56a..5c26baef9e 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -12,6 +12,7 @@
#include "clientmodel.h"
#include "guiconstants.h"
#include "guiutil.h"
+#include "modaloverlay.h"
#include "networkstyle.h"
#include "notificator.h"
#include "openuridialog.h"
@@ -30,6 +31,7 @@
#include "macdockiconhandler.h"
#endif
+#include "chainparams.h"
#include "init.h"
#include "ui_interface.h"
#include "util.h"
@@ -45,7 +47,6 @@
#include <QMenuBar>
#include <QMessageBox>
#include <QMimeData>
-#include <QProgressBar>
#include <QProgressDialog>
#include <QSettings>
#include <QShortcut>
@@ -73,15 +74,19 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
#endif
;
+/** Display name for default wallet name. Uses tilde to avoid name
+ * collisions in the future with additional wallets */
const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
-BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
+BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
QMainWindow(parent),
+ enableWallet(false),
clientModel(0),
walletFrame(0),
unitDisplayControl(0),
- labelEncryptionIcon(0),
- labelConnectionsIcon(0),
+ labelWalletEncryptionIcon(0),
+ labelWalletHDStatusIcon(0),
+ connectionsControl(0),
labelBlocksIcon(0),
progressBarLabel(0),
progressBar(0),
@@ -113,18 +118,16 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
notificator(0),
rpcConsole(0),
helpMessageDialog(0),
+ modalOverlay(0),
prevBlocks(0),
spinnerFrame(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
QString windowTitle = tr(PACKAGE_NAME) + " - ";
#ifdef ENABLE_WALLET
- /* if compiled with wallet support, -disablewallet can still disable the wallet */
- enableWallet = !GetBoolArg("-disablewallet", false);
-#else
- enableWallet = false;
+ enableWallet = WalletModel::isWalletEnabled();
#endif // ENABLE_WALLET
if(enableWallet)
{
@@ -147,13 +150,13 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
setUnifiedTitleAndToolBarOnMac(true);
#endif
- rpcConsole = new RPCConsole(platformStyle, 0);
+ rpcConsole = new RPCConsole(_platformStyle, 0);
helpMessageDialog = new HelpMessageDialog(this, false);
#ifdef ENABLE_WALLET
if(enableWallet)
{
/** Create wallet frame and make it the central widget */
- walletFrame = new WalletFrame(platformStyle, this);
+ walletFrame = new WalletFrame(_platformStyle, this);
setCentralWidget(walletFrame);
} else
#endif // ENABLE_WALLET
@@ -194,18 +197,20 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
frameBlocksLayout->setContentsMargins(3,0,3,0);
frameBlocksLayout->setSpacing(3);
unitDisplayControl = new UnitDisplayStatusBarControl(platformStyle);
- labelEncryptionIcon = new QLabel();
- labelConnectionsIcon = new QLabel();
- labelBlocksIcon = new QLabel();
+ labelWalletEncryptionIcon = new QLabel();
+ labelWalletHDStatusIcon = new QLabel();
+ connectionsControl = new GUIUtil::ClickableLabel();
+ labelBlocksIcon = new GUIUtil::ClickableLabel();
if(enableWallet)
{
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(unitDisplayControl);
frameBlocksLayout->addStretch();
- frameBlocksLayout->addWidget(labelEncryptionIcon);
+ frameBlocksLayout->addWidget(labelWalletEncryptionIcon);
+ frameBlocksLayout->addWidget(labelWalletHDStatusIcon);
}
frameBlocksLayout->addStretch();
- frameBlocksLayout->addWidget(labelConnectionsIcon);
+ frameBlocksLayout->addWidget(connectionsControl);
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelBlocksIcon);
frameBlocksLayout->addStretch();
@@ -238,6 +243,17 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
// Subscribe to notifications from core
subscribeToCoreSignals();
+
+ connect(connectionsControl, SIGNAL(clicked(QPoint)), this, SLOT(toggleNetworkActive()));
+
+ modalOverlay = new ModalOverlay(this->centralWidget());
+#ifdef ENABLE_WALLET
+ if(enableWallet) {
+ connect(walletFrame, SIGNAL(requestedSyncWarningInfo()), this, SLOT(showModalOverlay()));
+ connect(labelBlocksIcon, SIGNAL(clicked(QPoint)), this, SLOT(showModalOverlay()));
+ connect(progressBar, SIGNAL(clicked(QPoint)), this, SLOT(showModalOverlay()));
+ }
+#endif
}
BitcoinGUI::~BitcoinGUI()
@@ -448,38 +464,40 @@ void BitcoinGUI::createToolBars()
}
}
-void BitcoinGUI::setClientModel(ClientModel *clientModel)
+void BitcoinGUI::setClientModel(ClientModel *_clientModel)
{
- this->clientModel = clientModel;
- if(clientModel)
+ this->clientModel = _clientModel;
+ if(_clientModel)
{
// Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
// while the client has not yet fully loaded
createTrayIconMenu();
// Keep up to date with client
- setNumConnections(clientModel->getNumConnections());
- connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
+ updateNetworkState();
+ 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);
- connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
+ modalOverlay->setKnownBestHeight(_clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel->getHeaderTipTime()));
+ setNumBlocks(_clientModel->getNumBlocks(), _clientModel->getLastBlockDate(), _clientModel->getVerificationProgress(NULL), false);
+ connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
// Receive and report messages from client model
- connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
+ connect(_clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
// Show progress dialog
- connect(clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
+ connect(_clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
- rpcConsole->setClientModel(clientModel);
+ rpcConsole->setClientModel(_clientModel);
#ifdef ENABLE_WALLET
if(walletFrame)
{
- walletFrame->setClientModel(clientModel);
+ walletFrame->setClientModel(_clientModel);
}
#endif // ENABLE_WALLET
- unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
+ unitDisplayControl->setOptionsModel(_clientModel->getOptionsModel());
- OptionsModel* optionsModel = clientModel->getOptionsModel();
+ OptionsModel* optionsModel = _clientModel->getOptionsModel();
if(optionsModel)
{
// be aware of the tray icon disable state change reported by the OptionsModel object.
@@ -496,6 +514,15 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
// Disable context menu on tray icon
trayIconMenu->clear();
}
+ // Propagate cleared model to child objects
+ rpcConsole->setClientModel(nullptr);
+#ifdef ENABLE_WALLET
+ if (walletFrame)
+ {
+ walletFrame->setClientModel(nullptr);
+ }
+#endif // ENABLE_WALLET
+ unitDisplayControl->setOptionsModel(nullptr);
}
}
@@ -685,8 +712,9 @@ void BitcoinGUI::gotoVerifyMessageTab(QString addr)
}
#endif // ENABLE_WALLET
-void BitcoinGUI::setNumConnections(int count)
+void BitcoinGUI::updateNetworkState()
{
+ int count = clientModel->getNumConnections();
QString icon;
switch(count)
{
@@ -696,16 +724,55 @@ void BitcoinGUI::setNumConnections(int count)
case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
default: icon = ":/icons/connect_4"; break;
}
- labelConnectionsIcon->setPixmap(platformStyle->SingleColorIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
- labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
+
+ QString tooltip;
+
+ if (clientModel->getNetworkActive()) {
+ tooltip = tr("%n active connection(s) to Bitcoin network", "", count) + QString(".<br>") + tr("Click to disable network activity.");
+ } else {
+ tooltip = tr("Network activity disabled.") + QString("<br>") + tr("Click to enable network activity again.");
+ icon = ":/icons/network_disabled";
+ }
+
+ // Don't word-wrap this (fixed-width) tooltip
+ tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
+ connectionsControl->setToolTip(tooltip);
+
+ connectionsControl->setPixmap(platformStyle->SingleColorIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+}
+
+void BitcoinGUI::setNumConnections(int count)
+{
+ updateNetworkState();
+}
+
+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(!clientModel)
+ if (modalOverlay)
+ {
+ if (header)
+ modalOverlay->setKnownBestHeight(count, blockDate);
+ else
+ modalOverlay->tipUpdate(count, blockDate, nVerificationProgress);
+ }
+ 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
@@ -713,9 +780,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) {
@@ -731,8 +800,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;
}
@@ -751,7 +819,10 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
#ifdef ENABLE_WALLET
if(walletFrame)
+ {
walletFrame->showOutOfSyncWarning(false);
+ modalOverlay->showHide(true, true);
+ }
#endif // ENABLE_WALLET
progressBarLabel->setVisible(false);
@@ -759,30 +830,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
}
else
{
- // Represent time from last generated block in human readable text
- QString timeBehindText;
- const int HOUR_IN_SECONDS = 60*60;
- const int DAY_IN_SECONDS = 24*60*60;
- const int WEEK_IN_SECONDS = 7*24*60*60;
- const int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar
- if(secs < 2*DAY_IN_SECONDS)
- {
- timeBehindText = tr("%n hour(s)","",secs/HOUR_IN_SECONDS);
- }
- else if(secs < 2*WEEK_IN_SECONDS)
- {
- timeBehindText = tr("%n day(s)","",secs/DAY_IN_SECONDS);
- }
- else if(secs < YEAR_IN_SECONDS)
- {
- timeBehindText = tr("%n week(s)","",secs/WEEK_IN_SECONDS);
- }
- else
- {
- qint64 years = secs / YEAR_IN_SECONDS;
- qint64 remainder = secs % YEAR_IN_SECONDS;
- timeBehindText = tr("%1 and %2").arg(tr("%n year(s)", "", years)).arg(tr("%n week(s)","", remainder/WEEK_IN_SECONDS));
- }
+ QString timeBehindText = GUIUtil::formatNiceTimeOffset(secs);
progressBarLabel->setVisible(true);
progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
@@ -802,7 +850,10 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
#ifdef ENABLE_WALLET
if(walletFrame)
+ {
walletFrame->showOutOfSyncWarning(true);
+ modalOverlay->showHide();
+ }
#endif // ENABLE_WALLET
tooltip += QString("<br>");
@@ -902,17 +953,22 @@ void BitcoinGUI::closeEvent(QCloseEvent *event)
#ifndef Q_OS_MAC // Ignored on Mac
if(clientModel && clientModel->getOptionsModel())
{
- if(!clientModel->getOptionsModel()->getMinimizeToTray() &&
- !clientModel->getOptionsModel()->getMinimizeOnClose())
+ if(!clientModel->getOptionsModel()->getMinimizeOnClose())
{
// close rpcConsole in case it was open to make some space for the shutdown window
rpcConsole->close();
QApplication::quit();
}
+ else
+ {
+ QMainWindow::showMinimized();
+ event->ignore();
+ }
}
-#endif
+#else
QMainWindow::closeEvent(event);
+#endif
}
void BitcoinGUI::showEvent(QShowEvent *event)
@@ -983,28 +1039,37 @@ bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient)
return false;
}
+void BitcoinGUI::setHDStatus(int hdEnabled)
+{
+ labelWalletHDStatusIcon->setPixmap(platformStyle->SingleColorIcon(hdEnabled ? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelWalletHDStatusIcon->setToolTip(hdEnabled ? tr("HD key generation is <b>enabled</b>") : tr("HD key generation is <b>disabled</b>"));
+
+ // eventually disable the QLabel to set its opacity to 50%
+ labelWalletHDStatusIcon->setEnabled(hdEnabled);
+}
+
void BitcoinGUI::setEncryptionStatus(int status)
{
switch(status)
{
case WalletModel::Unencrypted:
- labelEncryptionIcon->hide();
+ labelWalletEncryptionIcon->hide();
encryptWalletAction->setChecked(false);
changePassphraseAction->setEnabled(false);
encryptWalletAction->setEnabled(true);
break;
case WalletModel::Unlocked:
- labelEncryptionIcon->show();
- labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
- labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
+ labelWalletEncryptionIcon->show();
+ labelWalletEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
break;
case WalletModel::Locked:
- labelEncryptionIcon->show();
- labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
- labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
+ labelWalletEncryptionIcon->show();
+ labelWalletEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
@@ -1084,6 +1149,12 @@ void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon)
}
}
+void BitcoinGUI::showModalOverlay()
+{
+ if (modalOverlay && (progressBar->isVisible() || modalOverlay->isLayerVisible()))
+ modalOverlay->toggleVisibility();
+}
+
static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style)
{
bool modal = (style & CClientUIInterface::MODAL);
@@ -1115,6 +1186,13 @@ void BitcoinGUI::unsubscribeFromCoreSignals()
uiInterface.ThreadSafeQuestion.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _3, _4));
}
+void BitcoinGUI::toggleNetworkActive()
+{
+ if (clientModel) {
+ clientModel->setNetworkActive(!clientModel->getNetworkActive());
+ }
+}
+
UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) :
optionsModel(0),
menu(0)
@@ -1142,7 +1220,7 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event)
/** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
void UnitDisplayStatusBarControl::createContextMenu()
{
- menu = new QMenu();
+ menu = new QMenu(this);
Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
{
QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this);
@@ -1153,17 +1231,17 @@ void UnitDisplayStatusBarControl::createContextMenu()
}
/** Lets the control know about the Options Model (and its signals) */
-void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *optionsModel)
+void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *_optionsModel)
{
- if (optionsModel)
+ if (_optionsModel)
{
- this->optionsModel = optionsModel;
+ this->optionsModel = _optionsModel;
// be aware of a display unit change reported by the OptionsModel object.
- connect(optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int)));
+ connect(_optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int)));
// initialize the display units label with the current value in the model.
- updateDisplayUnit(optionsModel->getDisplayUnit());
+ updateDisplayUnit(_optionsModel->getDisplayUnit());
}
}
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 12e7702ed8..62d419d3ef 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -29,6 +29,7 @@ class UnitDisplayStatusBarControl;
class WalletFrame;
class WalletModel;
class HelpMessageDialog;
+class ModalOverlay;
class CWallet;
@@ -82,8 +83,9 @@ private:
WalletFrame *walletFrame;
UnitDisplayStatusBarControl *unitDisplayControl;
- QLabel *labelEncryptionIcon;
- QLabel *labelConnectionsIcon;
+ QLabel *labelWalletEncryptionIcon;
+ QLabel *labelWalletHDStatusIcon;
+ QLabel *connectionsControl;
QLabel *labelBlocksIcon;
QLabel *progressBarLabel;
QProgressBar *progressBar;
@@ -117,6 +119,7 @@ private:
Notificator *notificator;
RPCConsole *rpcConsole;
HelpMessageDialog *helpMessageDialog;
+ ModalOverlay *modalOverlay;
/** Keep track of previous number of blocks, to detect progress */
int prevBlocks;
@@ -143,6 +146,11 @@ private:
/** Disconnect core signals from GUI client */
void unsubscribeFromCoreSignals();
+ /** 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);
@@ -150,6 +158,8 @@ Q_SIGNALS:
public Q_SLOTS:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
+ /** Set network state shown in the UI */
+ void setNetworkActive(bool networkActive);
/** Set number of blocks and last block date shown in the UI */
void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers);
@@ -169,6 +179,12 @@ public Q_SLOTS:
*/
void setEncryptionStatus(int status);
+ /** Set the hd-enabled status as shown in the UI.
+ @param[in] status current hd enabled status
+ @see WalletModel::EncryptionStatus
+ */
+ void setHDStatus(int hdEnabled);
+
bool handlePaymentRequest(const SendCoinsRecipient& recipient);
/** Show incoming transaction notification for new transactions. */
@@ -222,6 +238,11 @@ private Q_SLOTS:
/** When hideTrayIcon setting is changed in OptionsModel hide or show the icon accordingly. */
void setTrayIconVisible(bool);
+
+ /** Toggle networking */
+ void toggleNetworkActive();
+
+ void showModalOverlay();
};
class UnitDisplayStatusBarControl : public QLabel
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index bca5b72827..a1e5cccc0b 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -15,18 +15,15 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"(1 = keep tx meta data e.g. account owner and payment request information, 2 "
"= drop tx meta data)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"-fallbackfee is set very high! This is the transaction fee you may pay when "
-"fee estimates are not available."),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"-maxtxfee is set very high! Fees this large could be paid on a single "
"transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"-paytxfee is set very high! This is the transaction fee you will pay if you "
-"send a transaction."),
-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", ""
@@ -46,6 +43,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
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"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Create new files with system default permissions, instead of umask 077 (only "
"effective with disabled wallet functionality)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -55,11 +55,13 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Discover own IP addresses (default: 1 when listening and no -externalip or -"
"proxy)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Distributed under the MIT software license, see the accompanying file "
-"COPYING or <http://www.opensource.org/licenses/mit-license.php>."),
+"Distributed under the MIT software license, see the accompanying file %s or "
+"%s"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Do not keep transactions in the mempool longer than <n> hours (default: %u)"),
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"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error reading %s! All keys read correctly, but transaction data or address "
@@ -76,14 +78,17 @@ 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", ""
"Fees (in %s/kB) smaller than this are considered zero fee for transaction "
"creation (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Force relay of transactions from whitelisted peers even they violate local "
-"relay policy (default: %d)"),
+"Force relay of transactions from whitelisted peers even if they violate "
+"local relay policy (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"How thorough the block verification of -checkblocks is (0-4, default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -93,6 +98,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", ""
@@ -125,24 +134,34 @@ 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)"),
+"unless -connect/-noconnect)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Randomize credentials for every proxy connection. This enables Tor stream "
"isolation (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Reduce storage requirements by pruning (deleting) old blocks. This mode is "
-"incompatible with -txindex and -rescan. Warning: Reverting this setting "
-"requires re-downloading the entire blockchain. (default: 0 = disable pruning "
-"blocks, >%u = target size in MiB to use for block files)"),
+"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, >%u "
+"= automatically prune block files to stay under the specified target size in "
+"MiB)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Rescans are not possible in pruned mode. You will need to use -reindex which "
"will download the whole blockchain again."),
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", ""
+"Sets the serialization of raw transaction or block hex returned in non-"
+"verbose mode, non-segwit(0) or segwit(1) (default: %d)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Support filtering of blocks and transaction with bloom filters (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"The block database contains a block which appears to be from the future. "
@@ -155,9 +174,11 @@ 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 pay when fee estimates are not available."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"This product includes software developed by the OpenSSL Project for use in "
-"the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software "
-"written by Eric Young and UPnP software written by Thomas Bernard."),
+"the OpenSSL Toolkit %s and cryptographic software written by Eric Young and "
+"UPnP software written by Thomas Bernard."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Total length of network version string (%i) exceeds maximum length (%i). "
"Reduce the number or size of uacomments."),
@@ -184,7 +205,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Username and hashed password for JSON-RPC connections. The field <userpw> "
"comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is "
-"included in share/rpcuser. This option can be specified multiple times"),
+"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"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Wallet will not create transactions that violate mempool chain limits "
+"(default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: The network does not appear to fully agree! Some miners appear to "
"be experiencing issues."),
@@ -199,8 +225,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", ""
-"Whitelist peers connecting from the given netmask or IP address. Can be "
-"specified multiple times."),
+"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", ""
"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"),
@@ -210,12 +236,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
QT_TRANSLATE_NOOP("bitcoin-core", ""
"You need to rebuild the database using -reindex-chainstate to change -txindex"),
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", "-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"),
@@ -227,8 +253,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -%s address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Chain selection options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Change index out of range"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node(s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect through SOCKS5 proxy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, and disconnect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connection options:"),
@@ -273,6 +299,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s' (
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most <n> unconnectable transactions in memory (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Keep the transaction memory pool below <n> megabytes (default: %u)"),
+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..."),
@@ -284,7 +311,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most <n> connections to peers (de
QT_TRANSLATE_NOOP("bitcoin-core", "Make the wallet broadcast transactions"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Minimum bytes per sigop in transactions we relay and mine (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Node relay options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."),
@@ -309,9 +335,10 @@ 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)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum BIP141 block cost (default: %d)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum BIP141 block weight (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block size in bytes (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set the number of threads to service RPC calls (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Show all debugging options (usage: --help -help-debug)"),
@@ -324,14 +351,20 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify wallet file (within data directory)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Spend unconfirmed change when sending transactions (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Starting network threads..."),
QT_TRANSLATE_NOOP("bitcoin-core", "The source code is available from %s."),
QT_TRANSLATE_NOOP("bitcoin-core", "The transaction amount is too small to pay the fee"),
+QT_TRANSLATE_NOOP("bitcoin-core", "The wallet will avoid paying less than the minimum relay fee."),
QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."),
+QT_TRANSLATE_NOOP("bitcoin-core", "This is the minimum transaction fee you pay on every transaction."),
+QT_TRANSLATE_NOOP("bitcoin-core", "This is the transaction fee you will pay if you send a transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: %u)"),
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 be positive"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must not be negative"),
+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"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"),
@@ -343,6 +376,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -debugnet ignored, use -
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -tor found, use -onion."),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format on startup"),
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..."),
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 6490057897..4da414a4e3 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index fda067b0b8..6ef37de380 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
diff --git a/src/qt/callback.h b/src/qt/callback.h
new file mode 100644
index 0000000000..a8b593a652
--- /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:
+ 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 14661b857a..de00eacdb9 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -6,11 +6,14 @@
#include "bantablemodel.h"
#include "guiconstants.h"
+#include "guiutil.h"
#include "peertablemodel.h"
+#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "clientversion.h"
+#include "validation.h"
#include "net.h"
#include "txmempool.h"
#include "ui_interface.h"
@@ -27,13 +30,15 @@ static const int64_t nClientStartupTime = GetTime();
static int64_t nLastHeaderTipUpdateNotification = 0;
static int64_t nLastBlockTipUpdateNotification = 0;
-ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
+ClientModel::ClientModel(OptionsModel *_optionsModel, QObject *parent) :
QObject(parent),
- optionsModel(optionsModel),
+ optionsModel(_optionsModel),
peerTableModel(0),
banTableModel(0),
pollTimer(0)
{
+ cachedBestHeaderHeight = -1;
+ cachedBestHeaderTime = -1;
peerTableModel = new PeerTableModel(this);
banTableModel = new BanTableModel(this);
pollTimer = new QTimer(this);
@@ -50,16 +55,18 @@ ClientModel::~ClientModel()
int ClientModel::getNumConnections(unsigned int flags) const
{
- LOCK(cs_vNodes);
- if (flags == CONNECTIONS_ALL) // Shortcut if we want total
- return vNodes.size();
+ CConnman::NumConnections connections = CConnman::CONNECTIONS_NONE;
- int nNum = 0;
- BOOST_FOREACH(const CNode* pnode, vNodes)
- if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
- nNum++;
+ if(flags == CONNECTIONS_IN)
+ connections = CConnman::CONNECTIONS_IN;
+ else if (flags == CONNECTIONS_OUT)
+ connections = CConnman::CONNECTIONS_OUT;
+ else if (flags == CONNECTIONS_ALL)
+ connections = CConnman::CONNECTIONS_ALL;
- return nNum;
+ if(g_connman)
+ return g_connman->GetNodeCount(connections);
+ return 0;
}
int ClientModel::getNumBlocks() const
@@ -68,14 +75,44 @@ int ClientModel::getNumBlocks() const
return chainActive.Height();
}
+int ClientModel::getHeaderTipHeight() const
+{
+ 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
+{
+ if (cachedBestHeaderTime == -1) {
+ LOCK(cs_main);
+ if (pindexBestHeader) {
+ cachedBestHeaderHeight = pindexBestHeader->nHeight;
+ cachedBestHeaderTime = pindexBestHeader->GetBlockTime();
+ }
+ }
+ return cachedBestHeaderTime;
+}
+
quint64 ClientModel::getTotalBytesRecv() const
{
- return CNode::GetTotalBytesRecv();
+ if(!g_connman)
+ return 0;
+ return g_connman->GetTotalBytesRecv();
}
quint64 ClientModel::getTotalBytesSent() const
{
- return CNode::GetTotalBytesSent();
+ if(!g_connman)
+ return 0;
+ return g_connman->GetTotalBytesSent();
}
QDateTime ClientModel::getLastBlockDate() const
@@ -106,7 +143,7 @@ double ClientModel::getVerificationProgress(const CBlockIndex *tipIn) const
LOCK(cs_main);
tip = chainActive.Tip();
}
- return Checkpoints::GuessVerificationProgress(Params().Checkpoints(), tip);
+ return GuessVerificationProgress(Params().TxData(), tip);
}
void ClientModel::updateTimer()
@@ -122,6 +159,11 @@ void ClientModel::updateNumConnections(int numConnections)
Q_EMIT numConnectionsChanged(numConnections);
}
+void ClientModel::updateNetworkActive(bool networkActive)
+{
+ Q_EMIT networkActiveChanged(networkActive);
+}
+
void ClientModel::updateAlert()
{
Q_EMIT alertsChanged(getStatusBarWarnings());
@@ -144,6 +186,21 @@ enum BlockSource ClientModel::getBlockSource() const
return BLOCK_SOURCE_NONE;
}
+void ClientModel::setNetworkActive(bool active)
+{
+ if (g_connman) {
+ g_connman->SetNetworkActive(active);
+ }
+}
+
+bool ClientModel::getNetworkActive() const
+{
+ if (g_connman) {
+ return g_connman->GetNetworkActive();
+ }
+ return false;
+}
+
QString ClientModel::getStatusBarWarnings() const
{
return QString::fromStdString(GetWarnings("gui"));
@@ -186,7 +243,7 @@ QString ClientModel::formatClientStartupTime() const
QString ClientModel::dataDir() const
{
- return QString::fromStdString(GetDataDir().string());
+ return GUIUtil::boostPathToQString(GetDataDir());
}
void ClientModel::updateBanlist()
@@ -210,6 +267,12 @@ static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConn
Q_ARG(int, newNumConnections));
}
+static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkActive)
+{
+ QMetaObject::invokeMethod(clientmodel, "updateNetworkActive", Qt::QueuedConnection,
+ Q_ARG(bool, networkActive));
+}
+
static void NotifyAlertChanged(ClientModel *clientmodel)
{
qDebug() << "NotifyAlertChanged";
@@ -233,6 +296,11 @@ 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
@@ -250,6 +318,7 @@ void ClientModel::subscribeToCoreSignals()
// Connect signals to client
uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
+ uiInterface.NotifyNetworkActiveChanged.connect(boost::bind(NotifyNetworkActiveChanged, this, _1));
uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2, false));
@@ -261,6 +330,7 @@ void ClientModel::unsubscribeFromCoreSignals()
// Disconnect signals from client
uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
+ uiInterface.NotifyNetworkActiveChanged.disconnect(boost::bind(NotifyNetworkActiveChanged, this, _1));
uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this));
uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, false));
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 99fd574b9e..4c92e2144e 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -8,6 +8,8 @@
#include <QObject>
#include <QDateTime>
+#include <atomic>
+
class AddressTableModel;
class BanTableModel;
class OptionsModel;
@@ -51,7 +53,8 @@ public:
//! Return number of connections, default is in- and outbound (total)
int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const;
int getNumBlocks() const;
-
+ int getHeaderTipHeight() const;
+ int64_t getHeaderTipTime() const;
//! Return number of transactions in the mempool
long getMempoolSize() const;
//! Return the dynamic memory usage of the mempool
@@ -65,8 +68,12 @@ 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;
+ //! Toggle network activity state in core
+ void setNetworkActive(bool active);
//! Return warnings to be displayed in status bar
QString getStatusBarWarnings() const;
@@ -76,6 +83,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;
@@ -90,6 +101,7 @@ Q_SIGNALS:
void numConnectionsChanged(int count);
void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, bool header);
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes);
+ void networkActiveChanged(bool networkActive);
void alertsChanged(const QString &warnings);
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut);
@@ -102,6 +114,7 @@ Q_SIGNALS:
public Q_SLOTS:
void updateTimer();
void updateNumConnections(int numConnections);
+ void updateNetworkActive(bool networkActive);
void updateAlert();
void updateBanlist();
};
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 837f8ba6c1..2a331d4fae 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -13,9 +13,11 @@
#include "txmempool.h"
#include "walletmodel.h"
-#include "coincontrol.h"
+#include "wallet/coincontrol.h"
#include "init.h"
-#include "main.h" // For minRelayTxFee
+#include "policy/fees.h"
+#include "policy/policy.h"
+#include "validation.h" // For mempool
#include "wallet/wallet.h"
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
@@ -35,11 +37,18 @@ QList<CAmount> CoinControlDialog::payAmounts;
CCoinControl* CoinControlDialog::coinControl = new CCoinControl();
bool CoinControlDialog::fSubtractFeeFromAmount = false;
-CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent) :
+bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const {
+ int column = treeWidget()->sortColumn();
+ if (column == CoinControlDialog::COLUMN_AMOUNT || column == CoinControlDialog::COLUMN_DATE || column == CoinControlDialog::COLUMN_CONFIRMATIONS)
+ return data(column, Qt::UserRole).toLongLong() < other.data(column, Qt::UserRole).toLongLong();
+ return QTreeWidgetItem::operator<(other);
+}
+
+CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::CoinControlDialog),
model(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
ui->setupUi(this);
@@ -52,7 +61,7 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this
// context menu
- contextMenu = new QMenu();
+ contextMenu = new QMenu(this);
contextMenu->addAction(copyAddressAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(copyAmountAction);
@@ -76,7 +85,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
- QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
@@ -85,7 +93,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(clipboardFee()));
connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(clipboardAfterFee()));
connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(clipboardBytes()));
- connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(clipboardPriority()));
connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(clipboardLowOutput()));
connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(clipboardChange()));
@@ -94,7 +101,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
ui->labelCoinControlFee->addAction(clipboardFeeAction);
ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
ui->labelCoinControlBytes->addAction(clipboardBytesAction);
- ui->labelCoinControlPriority->addAction(clipboardPriorityAction);
ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
ui->labelCoinControlChange->addAction(clipboardChangeAction);
@@ -124,20 +130,16 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString());
ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84);
- ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100);
- ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170);
- ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 290);
- ui->treeWidget->setColumnWidth(COLUMN_DATE, 110);
- ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100);
- ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100);
+ ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 110);
+ ui->treeWidget->setColumnWidth(COLUMN_LABEL, 190);
+ ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 320);
+ ui->treeWidget->setColumnWidth(COLUMN_DATE, 130);
+ ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 110);
ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it
- ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it
- ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but don't show it
- ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but don't show it
// default view is sorted by amount desc
- sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder);
+ sortView(COLUMN_AMOUNT, Qt::DescendingOrder);
// restore list mode and sortorder as a convenience feature
QSettings settings;
@@ -157,27 +159,18 @@ CoinControlDialog::~CoinControlDialog()
delete ui;
}
-void CoinControlDialog::setModel(WalletModel *model)
+void CoinControlDialog::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
- if(model && model->getOptionsModel() && model->getAddressTableModel())
+ if(_model && _model->getOptionsModel() && _model->getAddressTableModel())
{
updateView();
updateLabelLocked();
- CoinControlDialog::updateLabels(model, this);
+ CoinControlDialog::updateLabels(_model, this);
}
}
-// helper function str_pad
-QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding)
-{
- while (s.length() < nPadLength)
- s = sPadding + s;
-
- return s;
-}
-
// ok button
void CoinControlDialog::buttonBoxClicked(QAbstractButton* button)
{
@@ -325,12 +318,6 @@ void CoinControlDialog::clipboardBytes()
GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));
}
-// copy label "Priority" to clipboard
-void CoinControlDialog::clipboardPriority()
-{
- GUIUtil::setClipboard(ui->labelCoinControlPriority->text());
-}
-
// copy label "Dust" to clipboard
void CoinControlDialog::clipboardLowOutput()
{
@@ -349,7 +336,7 @@ void CoinControlDialog::sortView(int column, Qt::SortOrder order)
sortColumn = column;
sortOrder = order;
ui->treeWidget->sortItems(column, order);
- ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder);
+ ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);
}
// treeview: clicked on header
@@ -357,12 +344,10 @@ void CoinControlDialog::headerSectionClicked(int logicalIndex)
{
if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing
{
- ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder);
+ ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);
}
else
{
- logicalIndex = getMappedColumn(logicalIndex, false);
-
if (sortColumn == logicalIndex)
sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder);
else
@@ -419,25 +404,6 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
#endif
}
-// return human readable label for priority number
-QString CoinControlDialog::getPriorityLabel(double dPriority, double mempoolEstimatePriority)
-{
- double dPriorityMedium = mempoolEstimatePriority;
-
- if (dPriorityMedium <= 0)
- dPriorityMedium = AllowFreeThreshold(); // not enough data, back to hard-coded
-
- if (dPriority / 1000000 > dPriorityMedium) return tr("highest");
- else if (dPriority / 100000 > dPriorityMedium) return tr("higher");
- else if (dPriority / 10000 > dPriorityMedium) return tr("high");
- else if (dPriority / 1000 > dPriorityMedium) return tr("medium-high");
- else if (dPriority > dPriorityMedium) return tr("medium");
- else if (dPriority * 10 > dPriorityMedium) return tr("low-medium");
- else if (dPriority * 100 > dPriorityMedium) return tr("low");
- else if (dPriority * 1000 > dPriorityMedium) return tr("lower");
- else return tr("lowest");
-}
-
// shows count of locked unspent outputs
void CoinControlDialog::updateLabelLocked()
{
@@ -468,23 +434,17 @@ 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(::minRelayTxFee))
- fDust = true;
+ fDust |= IsDust(txout, ::dustRelayFee);
}
}
- QString sPriorityLabel = tr("none");
CAmount nAmount = 0;
CAmount nPayFee = 0;
CAmount nAfterFee = 0;
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;
@@ -507,29 +467,24 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nQuantity++;
// Amount
- nAmount += out.tx->vout[out.i].nValue;
-
- // Priority
- dPriorityInputs += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
+ nAmount += out.tx->tx->vout[out.i].nValue;
// Bytes
CTxDestination address;
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
- if (out.tx->vout[out.i].scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram))
+ if (out.tx->tx->vout[out.i].scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram))
{
nBytesInputs += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
fWitness = true;
}
- else if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
+ else if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address))
{
CPubKey pubkey;
CKeyID *keyid = boost::get<CKeyID>(&address);
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
@@ -551,30 +506,16 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes += nQuantity; // account for the witness byte that holds the number of stack items for each input.
}
- // Priority
- 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)
- sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority);
-
// in the subtract fee from amount case, we can tell if zero change already and subtract the bytes, so that fee calculation afterwards is accurate
if (CoinControlDialog::fSubtractFeeFromAmount)
if (nAmount - nPayAmount == 0)
nBytes -= 34;
// Fee
- nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
+ nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, ::mempool, ::feeEstimator);
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 dPriorityNeeded = std::max(mempoolEstimatePriority, AllowFreeThreshold());
- fAllowFree = (dPriority >= dPriorityNeeded);
-
- if (fSendFreeTransactions)
- if (fAllowFree && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
- nPayFee = 0;
-
if (nPayAmount > 0)
{
nChange = nAmount - nPayAmount;
@@ -585,10 +526,10 @@ 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(::minRelayTxFee))
+ if (IsDust(txout, ::dustRelayFee))
{
if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust
- nChange = txout.GetDustThreshold(::minRelayTxFee);
+ nChange = GetDustThreshold(txout, ::dustRelayFee);
else
{
nPayFee += nChange;
@@ -602,9 +543,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
@@ -617,7 +556,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
QLabel *l3 = dialog->findChild<QLabel *>("labelCoinControlFee");
QLabel *l4 = dialog->findChild<QLabel *>("labelCoinControlAfterFee");
QLabel *l5 = dialog->findChild<QLabel *>("labelCoinControlBytes");
- QLabel *l6 = dialog->findChild<QLabel *>("labelCoinControlPriority");
QLabel *l7 = dialog->findChild<QLabel *>("labelCoinControlLowOutput");
QLabel *l8 = dialog->findChild<QLabel *>("labelCoinControlChange");
@@ -633,7 +571,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee
l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee
l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes
- l6->setText(sPriorityLabel); // Priority
l7->setText(fDust ? tr("yes") : tr("no")); // Dust
l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
if (nPayFee > 0 && (coinControl->nMinimumTotalFee < nPayFee))
@@ -644,41 +581,28 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l8->setText(ASYMP_UTF8 + l8->text());
}
- // turn labels "red"
- l5->setStyleSheet((nBytes >= MAX_FREE_TRANSACTION_CREATE_SIZE) ? "color:red;" : "");// Bytes >= 1000
- l6->setStyleSheet((dPriority > 0 && !fAllowFree) ? "color:red;" : ""); // Priority < "medium"
- l7->setStyleSheet((fDust) ? "color:red;" : ""); // Dust = "yes"
+ // turn label red when dust
+ l7->setStyleSheet((fDust) ? "color:red;" : "");
// tool tips
- QString toolTip1 = tr("This label turns red if the transaction size is greater than 1000 bytes.") + "<br /><br />";
- toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))) + "<br /><br />";
- toolTip1 += tr("Can vary +/- 1 byte per input.");
-
- QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />";
- toolTip2 += tr("This label turns red if the priority is smaller than \"medium\".") + "<br /><br />";
- toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000)));
-
- QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
+ 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;
+ dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), ::feeEstimator.estimateSmartFee(nTxConfirmTarget, NULL, ::mempool).GetFeePerK()) / 1000;
}
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
l3->setToolTip(toolTip4);
l4->setToolTip(toolTip4);
- l5->setToolTip(toolTip1);
- l6->setToolTip(toolTip2);
- l7->setToolTip(toolTip3);
+ l7->setToolTip(toolTipDust);
l8->setToolTip(toolTip4);
dialog->findChild<QLabel *>("labelCoinControlFeeText") ->setToolTip(l3->toolTip());
dialog->findChild<QLabel *>("labelCoinControlAfterFeeText") ->setToolTip(l4->toolTip());
dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip());
- dialog->findChild<QLabel *>("labelCoinControlPriorityText") ->setToolTip(l6->toolTip());
dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip());
dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setToolTip(l8->toolTip());
@@ -702,13 +626,12 @@ void CoinControlDialog::updateView()
QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
- double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
std::map<QString, std::vector<COutput> > mapCoins;
model->listCoins(mapCoins);
BOOST_FOREACH(const PAIRTYPE(QString, std::vector<COutput>)& coins, mapCoins) {
- QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem();
+ CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem();
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
QString sWalletAddress = coins.first;
QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress);
@@ -731,35 +654,27 @@ void CoinControlDialog::updateView()
}
CAmount nSum = 0;
- double dPrioritySum = 0;
int nChildren = 0;
- int nInputSum = 0;
BOOST_FOREACH(const COutput& out, coins.second) {
- int nInputSize = 0;
- nSum += out.tx->vout[out.i].nValue;
+ nSum += out.tx->tx->vout[out.i].nValue;
nChildren++;
- QTreeWidgetItem *itemOutput;
- if (treeMode) itemOutput = new QTreeWidgetItem(itemWalletAddress);
- else itemOutput = new QTreeWidgetItem(ui->treeWidget);
+ CCoinControlWidgetItem *itemOutput;
+ if (treeMode) itemOutput = new CCoinControlWidgetItem(itemWalletAddress);
+ else itemOutput = new CCoinControlWidgetItem(ui->treeWidget);
itemOutput->setFlags(flgCheckbox);
itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked);
// address
CTxDestination outputAddress;
QString sAddress = "";
- if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, outputAddress))
+ if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress))
{
sAddress = QString::fromStdString(CBitcoinAddress(outputAddress).ToString());
// if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs
if (!treeMode || (!(sAddress == sWalletAddress)))
itemOutput->setText(COLUMN_ADDRESS, sAddress);
-
- CPubKey pubkey;
- CKeyID *keyid = boost::get<CKeyID>(&outputAddress);
- if (keyid && model->getPubKey(*keyid, pubkey) && !pubkey.IsCompressed())
- nInputSize = 29; // 29 = 180 - 151 (public key is 180 bytes, priority free area is 151 bytes)
}
// label
@@ -778,22 +693,16 @@ void CoinControlDialog::updateView()
}
// amount
- itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue));
- itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(out.tx->vout[out.i].nValue), 15, " ")); // padding so that sorting works correctly
+ itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->tx->vout[out.i].nValue));
+ itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->tx->vout[out.i].nValue)); // padding so that sorting works correctly
// date
itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime()));
- itemOutput->setText(COLUMN_DATE_INT64, strPad(QString::number(out.tx->GetTxTime()), 20, " "));
+ itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong)out.tx->GetTxTime()));
// confirmations
- itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " "));
-
- // priority
- double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10
- itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority));
- itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " "));
- dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
- nInputSum += nInputSize;
+ itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.nDepth));
+ itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong)out.nDepth));
// transaction hash
uint256 txhash = out.tx->GetHash();
@@ -819,12 +728,9 @@ void CoinControlDialog::updateView()
// amount
if (treeMode)
{
- dPrioritySum = dPrioritySum / (nInputSum + 78);
itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
- itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
- itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum, mempoolEstimatePriority));
- itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " "));
+ itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)nSum));
}
}
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 1a467eb2ff..0b8162f858 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -28,6 +28,17 @@ namespace Ui {
#define ASYMP_UTF8 "\xE2\x89\x88"
+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) {}
+
+ bool operator<(const QTreeWidgetItem &other) const;
+};
+
+
class CoinControlDialog : public QDialog
{
Q_OBJECT
@@ -40,7 +51,6 @@ public:
// static because also called from sendcoinsdialog
static void updateLabels(WalletModel*, QDialog*);
- static QString getPriorityLabel(double dPriority, double mempoolEstimatePriority);
static QList<CAmount> payAmounts;
static CCoinControl *coinControl;
@@ -60,50 +70,21 @@ private:
const PlatformStyle *platformStyle;
- QString strPad(QString, int, QString);
void sortView(int, Qt::SortOrder);
void updateView();
enum
{
- COLUMN_CHECKBOX,
+ COLUMN_CHECKBOX = 0,
COLUMN_AMOUNT,
COLUMN_LABEL,
COLUMN_ADDRESS,
COLUMN_DATE,
COLUMN_CONFIRMATIONS,
- COLUMN_PRIORITY,
COLUMN_TXHASH,
COLUMN_VOUT_INDEX,
- COLUMN_AMOUNT_INT64,
- COLUMN_PRIORITY_INT64,
- COLUMN_DATE_INT64
};
-
- // some columns have a hidden column containing the value used for sorting
- int getMappedColumn(int column, bool fVisibleColumn = true)
- {
- if (fVisibleColumn)
- {
- if (column == COLUMN_AMOUNT_INT64)
- return COLUMN_AMOUNT;
- else if (column == COLUMN_PRIORITY_INT64)
- return COLUMN_PRIORITY;
- else if (column == COLUMN_DATE_INT64)
- return COLUMN_DATE;
- }
- else
- {
- if (column == COLUMN_AMOUNT)
- return COLUMN_AMOUNT_INT64;
- else if (column == COLUMN_PRIORITY)
- return COLUMN_PRIORITY_INT64;
- else if (column == COLUMN_DATE)
- return COLUMN_DATE_INT64;
- }
-
- return column;
- }
+ friend class CCoinControlWidgetItem;
private Q_SLOTS:
void showMenu(const QPoint &);
@@ -118,7 +99,6 @@ private Q_SLOTS:
void clipboardFee();
void clipboardAfterFee();
void clipboardBytes();
- void clipboardPriority();
void clipboardLowOutput();
void clipboardChange();
void radioTreeMode(bool);
diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp
index 8a1a49bb06..df59927782 100644
--- a/src/qt/csvmodelwriter.cpp
+++ b/src/qt/csvmodelwriter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2014 The Bitcoin Core developers
+// 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.
@@ -8,15 +8,15 @@
#include <QFile>
#include <QTextStream>
-CSVModelWriter::CSVModelWriter(const QString &filename, QObject *parent) :
+CSVModelWriter::CSVModelWriter(const QString &_filename, QObject *parent) :
QObject(parent),
- filename(filename), model(0)
+ filename(_filename), model(0)
{
}
-void CSVModelWriter::setModel(const QAbstractItemModel *model)
+void CSVModelWriter::setModel(const QAbstractItemModel *_model)
{
- this->model = model;
+ this->model = _model;
}
void CSVModelWriter::addColumn(const QString &title, int column, int role)
diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp
index 5f45031e9e..bb03c12f2d 100644
--- a/src/qt/editaddressdialog.cpp
+++ b/src/qt/editaddressdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2014 The Bitcoin Core developers
+// 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.
@@ -11,11 +11,11 @@
#include <QDataWidgetMapper>
#include <QMessageBox>
-EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) :
+EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) :
QDialog(parent),
ui(new Ui::EditAddressDialog),
mapper(0),
- mode(mode),
+ mode(_mode),
model(0)
{
ui->setupUi(this);
@@ -49,13 +49,13 @@ EditAddressDialog::~EditAddressDialog()
delete ui;
}
-void EditAddressDialog::setModel(AddressTableModel *model)
+void EditAddressDialog::setModel(AddressTableModel *_model)
{
- this->model = model;
- if(!model)
+ this->model = _model;
+ if(!_model)
return;
- mapper->setModel(model);
+ mapper->setModel(_model);
mapper->addMapping(ui->labelEdit, AddressTableModel::Label);
mapper->addMapping(ui->addressEdit, AddressTableModel::Address);
}
@@ -137,8 +137,8 @@ QString EditAddressDialog::getAddress() const
return address;
}
-void EditAddressDialog::setAddress(const QString &address)
+void EditAddressDialog::setAddress(const QString &_address)
{
- this->address = address;
- ui->addressEdit->setText(address);
+ this->address = _address;
+ ui->addressEdit->setText(_address);
}
diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui
index c1fef6b9b1..1ea00eb5c3 100644
--- a/src/qt/forms/coincontroldialog.ui
+++ b/src/qt/forms/coincontroldialog.ui
@@ -140,7 +140,10 @@
</widget>
</item>
<item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlPriorityText">
+ <widget class="QLabel" name="labelCoinControlLowOutputText">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="font">
<font>
<weight>75</weight>
@@ -148,12 +151,15 @@
</font>
</property>
<property name="text">
- <string>Priority:</string>
+ <string>Dust:</string>
</property>
</widget>
</item>
<item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlPriority">
+ <widget class="QLabel" name="labelCoinControlLowOutput">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -161,7 +167,7 @@
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="text">
- <string notr="true">medium</string>
+ <string notr="true">no</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -213,41 +219,6 @@
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlLowOutputText">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Dust:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlLowOutput">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="contextMenuPolicy">
- <enum>Qt::ActionsContextMenu</enum>
- </property>
- <property name="text">
- <string notr="true">no</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
</layout>
</item>
<item>
@@ -431,7 +402,7 @@
<bool>false</bool>
</property>
<property name="columnCount">
- <number>12</number>
+ <number>10</number>
</property>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>true</bool>
@@ -474,16 +445,6 @@
</column>
<column>
<property name="text">
- <string>Priority</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string/>
- </property>
- </column>
- <column>
- <property name="text">
<string/>
</property>
</column>
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 9dc641979e..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>
@@ -1353,13 +1353,36 @@
</widget>
</item>
<item row="16" column="0">
+ <widget class="QLabel" name="peerMinPingLabel">
+ <property name="text">
+ <string>Min Ping</string>
+ </property>
+ </widget>
+ </item>
+ <item row="16" column="2">
+ <widget class="QLabel" name="peerMinPing">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="17" column="0">
<widget class="QLabel" name="label_timeoffset">
<property name="text">
<string>Time Offset</string>
</property>
</widget>
</item>
- <item row="16" column="2">
+ <item row="17" column="2">
<widget class="QLabel" name="timeoffset">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1375,7 +1398,7 @@
</property>
</widget>
</item>
- <item row="17" column="1">
+ <item row="18" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
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/modaloverlay.ui b/src/qt/forms/modaloverlay.ui
new file mode 100644
index 0000000000..65a7a6c77e
--- /dev/null
+++ b/src/qt/forms/modaloverlay.ui
@@ -0,0 +1,376 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ModalOverlay</class>
+ <widget class="ModalOverlay" name="ModalOverlay">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>640</width>
+ <height>385</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="bgWidget" native="true">
+ <property name="styleSheet">
+ <string notr="true">#bgWidget { background: rgba(0,0,0,220); }</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayoutMain" stretch="1">
+ <property name="leftMargin">
+ <number>60</number>
+ </property>
+ <property name="topMargin">
+ <number>60</number>
+ </property>
+ <property name="rightMargin">
+ <number>60</number>
+ </property>
+ <property name="bottomMargin">
+ <number>60</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="contentWidget" native="true">
+ <property name="styleSheet">
+ <string notr="true">#contentWidget { background: rgba(255,255,255,240); border-radius: 6px; }
+
+QLabel { color: rgb(40,40,40); }</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayoutSub" stretch="1,0,0,0">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>10</number>
+ </property>
+ <property name="topMargin">
+ <number>10</number>
+ </property>
+ <property name="rightMargin">
+ <number>10</number>
+ </property>
+ <property name="bottomMargin">
+ <number>10</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayoutIconText" stretch="0,1">
+ <property name="topMargin">
+ <number>20</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayoutIcon">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="warningIcon">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/icons/warning</normaloff>
+ <disabledoff>:/icons/warning</disabledoff>:/icons/warning</iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>48</width>
+ <height>48</height>
+ </size>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacerWarningIcon">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayoutInfoText">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="infoText">
+ <property name="text">
+ <string>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.</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="infoTextStrong">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacerInTextSpace">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacerAfterText">
+ <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="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::FieldsStayAtSizeHint</enum>
+ </property>
+ <property name="horizontalSpacing">
+ <number>6</number>
+ </property>
+ <property name="verticalSpacing">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>10</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelNumberOfBlocksLeft">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Number of blocks left</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="numberOfBlocksLeft">
+ <property name="text">
+ <string>Unknown...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelLastBlockTime">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Last block time</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="newestBlockDate">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Unknown...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="labelSyncDone">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Progress</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayoutSync" stretch="0,1">
+ <item>
+ <widget class="QLabel" name="percentageProgress">
+ <property name="text">
+ <string notr="true">~</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="progressBar">
+ <property name="value">
+ <number>24</number>
+ </property>
+ <property name="format">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="labelProgressIncrease">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Progress increase per hour</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="progressIncreasePerH">
+ <property name="text">
+ <string>calculating...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="labelEstimatedTimeLeft">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Estimated time left until synced</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLabel" name="expectedTimeLeft">
+ <property name="text">
+ <string>calculating...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayoutButtons">
+ <property name="leftMargin">
+ <number>10</number>
+ </property>
+ <property name="topMargin">
+ <number>10</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <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="QPushButton" name="closeButton">
+ <property name="text">
+ <string>Hide</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ModalOverlay</class>
+ <extends>QWidget</extends>
+ <header>modaloverlay.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 0b29201872..0f1b3f4a73 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -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/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 6d792d1475..710801ee96 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -20,7 +20,7 @@
<bool>false</bool>
</property>
<property name="styleSheet">
- <string notr="true">background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000;</string>
+ <string notr="true">QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; }</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -28,6 +28,9 @@
<property name="margin">
<number>3</number>
</property>
+ <property name="textInteractionFlags">
+ <set>Qt::TextSelectableByMouse</set>
+ </property>
</widget>
</item>
<item>
@@ -61,7 +64,7 @@
<item>
<widget class="QPushButton" name="labelWalletStatus">
<property name="enabled">
- <bool>false</bool>
+ <bool>true</bool>
</property>
<property name="maximumSize">
<size>
@@ -447,7 +450,7 @@
<item>
<widget class="QPushButton" name="labelTransactionsStatus">
<property name="enabled">
- <bool>false</bool>
+ <bool>true</bool>
</property>
<property name="maximumSize">
<size>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 12d6a62c08..52256ca5c4 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -332,7 +332,7 @@
</widget>
</item>
<item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlPriorityText">
+ <widget class="QLabel" name="labelCoinControlLowOutputText">
<property name="font">
<font>
<weight>75</weight>
@@ -340,12 +340,12 @@
</font>
</property>
<property name="text">
- <string>Priority:</string>
+ <string>Dust:</string>
</property>
</widget>
</item>
<item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlPriority">
+ <widget class="QLabel" name="labelCoinControlLowOutput">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -353,7 +353,7 @@
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="text">
- <string notr="true">medium</string>
+ <string notr="true">no</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -411,35 +411,6 @@
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlLowOutputText">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Dust:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlLowOutput">
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="contextMenuPolicy">
- <enum>Qt::ActionsContextMenu</enum>
- </property>
- <property name="text">
- <string notr="true">no</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
</layout>
</item>
<item>
@@ -789,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 your 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>
@@ -1060,7 +1053,7 @@
<item>
<widget class="QLabel" name="labelSmartFee3">
<property name="text">
- <string>Confirmation time:</string>
+ <string>Confirmation time target:</string>
</property>
<property name="margin">
<number>2</number>
@@ -1093,7 +1086,7 @@
<number>0</number>
</property>
<property name="maximum">
- <number>24</number>
+ <number>23</number>
</property>
<property name="pageStep">
<number>1</number>
@@ -1125,6 +1118,26 @@
</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>
+ </item>
+ <item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -1167,6 +1180,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>
@@ -1177,8 +1200,8 @@
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>800</width>
- <height>1</height>
+ <width>40</width>
+ <height>5</height>
</size>
</property>
</spacer>
@@ -1212,7 +1235,7 @@
<bool>false</bool>
</property>
<property name="default">
- <bool>true</bool>
+ <bool>false</bool>
</property>
</widget>
</item>
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index bab9923d20..1d21d8c766 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 947a4c6821..bffa81137b 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -9,9 +9,10 @@
#include "qvalidatedlineedit.h"
#include "walletmodel.h"
+#include "fs.h"
#include "primitives/transaction.h"
#include "init.h"
-#include "main.h" // For minRelayTxFee
+#include "policy/policy.h"
#include "protocol.h"
#include "script/script.h"
#include "script/standard.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>
@@ -55,6 +51,7 @@
#include <QSettings>
#include <QTextDocument> // for Qt::mightBeRichText
#include <QThread>
+#include <QMouseEvent>
#if QT_VERSION < 0x050000
#include <QUrl>
@@ -66,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;
@@ -116,7 +111,7 @@ static std::string DummyAddress(const CChainParams &params)
std::vector<unsigned char> sourcedata = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata));
for(int i=0; i<256; ++i) { // Try every trailing byte
- std::string s = EncodeBase58(begin_ptr(sourcedata), end_ptr(sourcedata));
+ std::string s = EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size());
if (!CBitcoinAddress(s).IsValid())
return s;
sourcedata[sourcedata.size()-1] += 1;
@@ -256,7 +251,7 @@ bool isDust(const QString& address, const CAmount& amount)
CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
CScript script = GetScriptForDestination(dest);
CTxOut txOut(amount, script);
- return txOut.IsDust(::minRelayTxFee);
+ return IsDust(txOut, ::dustRelayFee);
}
QString HtmlEscape(const QString& str, bool fMultiLine)
@@ -291,17 +286,11 @@ void copyEntryData(QAbstractItemView *view, int column, int role)
}
}
-QString getEntryData(QAbstractItemView *view, int column, int role)
+QList<QModelIndex> getEntryData(QAbstractItemView *view, int column)
{
if(!view || !view->selectionModel())
- return QString();
- QModelIndexList selection = view->selectionModel()->selectedRows(column);
-
- if(!selection.isEmpty()) {
- // Return first item
- return (selection.at(0).data(role).toString());
- }
- return QString();
+ return QList<QModelIndex>();
+ return view->selectionModel()->selectedRows(column);
}
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
@@ -419,13 +408,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)
@@ -452,7 +457,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");
@@ -462,9 +467,9 @@ void SubstituteFonts(const QString& language)
#endif
}
-ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) :
+ToolTipToRichTextFilter::ToolTipToRichTextFilter(int _size_threshold, QObject *parent) :
QObject(parent),
- size_threshold(size_threshold)
+ size_threshold(_size_threshold)
{
}
@@ -541,7 +546,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();
@@ -575,7 +580,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()
{
@@ -591,7 +596,8 @@ void TableViewLastColumnResizingFixer::on_geometriesChanged()
* Initializes all internal variables and prepares the
* the resize modes of the last 2 columns of the table and
*/
-TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth) :
+TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent) :
+ QObject(parent),
tableView(table),
lastColumnMinimumWidth(lastColMinimumWidth),
allColumnsMinimumWidth(allColsMinimumWidth)
@@ -605,7 +611,7 @@ TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* t
}
#ifdef WIN32
-boost::filesystem::path static StartupShortcutPath()
+fs::path static StartupShortcutPath()
{
std::string chain = ChainNameFromCommandLine();
if (chain == CBaseChainParams::MAIN)
@@ -618,13 +624,13 @@ 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)
{
@@ -694,10 +700,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");
@@ -705,7 +709,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)
@@ -715,7 +719,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":
@@ -735,7 +739,7 @@ bool GetStartOnSystemStartup()
bool SetStartOnSystemStartup(bool fAutoStart)
{
if (!fAutoStart)
- boost::filesystem::remove(GetAutostartFilePath());
+ fs::remove(GetAutostartFilePath());
else
{
char pszExePath[MAX_PATH+1];
@@ -743,9 +747,9 @@ bool SetStartOnSystemStartup(bool fAutoStart)
if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
return false;
- 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();
@@ -766,6 +770,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>
@@ -828,6 +834,7 @@ bool SetStartOnSystemStartup(bool fAutoStart)
}
return true;
}
+#pragma GCC diagnostic pop
#else
bool GetStartOnSystemStartup() { return false; }
@@ -848,14 +855,17 @@ void restoreWindowGeometry(const QString& strSetting, const QSize& defaultSize,
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);
+
+ if ((!pos.x() && !pos.y()) || (QApplication::desktop()->screenNumber(parent) == -1))
+ {
+ QRect screen = QApplication::desktop()->screenGeometry();
+ QPoint defaultPos((screen.width() - defaultSize.width()) / 2,
+ (screen.height() - defaultSize.height()) / 2);
+ parent->resize(defaultSize);
+ parent->move(defaultPos);
+ }
}
void setClipboard(const QString& str)
@@ -864,28 +874,15 @@ void setClipboard(const QString& str)
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)
{
@@ -930,6 +927,9 @@ QString formatServicesStr(quint64 mask)
case NODE_WITNESS:
strList.append("WITNESS");
break;
+ case NODE_XTHIN:
+ strList.append("XTHIN");
+ break;
default:
strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check));
}
@@ -944,7 +944,7 @@ QString formatServicesStr(quint64 mask)
QString formatPingTime(double dPingTime)
{
- return dPingTime == 0 ? QObject::tr("N/A") : QString(QObject::tr("%1 ms")).arg(QString::number((int)(dPingTime * 1000), 10));
+ return (dPingTime == std::numeric_limits<int64_t>::max()/1e6 || dPingTime == 0) ? QObject::tr("N/A") : QString(QObject::tr("%1 ms")).arg(QString::number((int)(dPingTime * 1000), 10));
}
QString formatTimeOffset(int64_t nTimeOffset)
@@ -952,4 +952,51 @@ QString formatTimeOffset(int64_t nTimeOffset)
return QString(QObject::tr("%1 s")).arg(QString::number((int)nTimeOffset, 10));
}
+QString formatNiceTimeOffset(qint64 secs)
+{
+ // Represent time from last generated block in human readable text
+ QString timeBehindText;
+ const int HOUR_IN_SECONDS = 60*60;
+ const int DAY_IN_SECONDS = 24*60*60;
+ const int WEEK_IN_SECONDS = 7*24*60*60;
+ const int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar
+ if(secs < 60)
+ {
+ timeBehindText = QObject::tr("%n second(s)","",secs);
+ }
+ else if(secs < 2*HOUR_IN_SECONDS)
+ {
+ timeBehindText = QObject::tr("%n minute(s)","",secs/60);
+ }
+ else if(secs < 2*DAY_IN_SECONDS)
+ {
+ timeBehindText = QObject::tr("%n hour(s)","",secs/HOUR_IN_SECONDS);
+ }
+ else if(secs < 2*WEEK_IN_SECONDS)
+ {
+ timeBehindText = QObject::tr("%n day(s)","",secs/DAY_IN_SECONDS);
+ }
+ else if(secs < YEAR_IN_SECONDS)
+ {
+ timeBehindText = QObject::tr("%n week(s)","",secs/WEEK_IN_SECONDS);
+ }
+ else
+ {
+ qint64 years = secs / YEAR_IN_SECONDS;
+ qint64 remainder = secs % YEAR_IN_SECONDS;
+ timeBehindText = QObject::tr("%1 and %2").arg(QObject::tr("%n year(s)", "", years)).arg(QObject::tr("%n week(s)","", remainder/WEEK_IN_SECONDS));
+ }
+ return timeBehindText;
+}
+
+void ClickableLabel::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_EMIT clicked(event->pos());
+}
+
+void ClickableProgressBar::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_EMIT clicked(event->pos());
+}
+
} // namespace GUIUtil
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 9267e0a6c9..d6aa8c4ea6 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -6,6 +6,7 @@
#define BITCOIN_QT_GUIUTIL_H
#include "amount.h"
+#include "fs.h"
#include <QEvent>
#include <QHeaderView>
@@ -14,8 +15,7 @@
#include <QProgressBar>
#include <QString>
#include <QTableView>
-
-#include <boost/filesystem.hpp>
+#include <QLabel>
class QValidatedLineEdit;
class SendCoinsRecipient;
@@ -67,10 +67,9 @@ namespace GUIUtil
/** Return a field of the currently selected entry as a QString. Does nothing if nothing
is selected.
@param[in] column Data column to extract from the model
- @param[in] role Data role to extract from the model
@see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
*/
- QString getEntryData(QAbstractItemView *view, int column, int role);
+ QList<QModelIndex> getEntryData(QAbstractItemView *view, int column);
void setClipboard(const QString& str);
@@ -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.
*
@@ -150,7 +152,7 @@ namespace GUIUtil
Q_OBJECT
public:
- TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth);
+ TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent);
void stretchColumnWidth(int column);
private:
@@ -183,10 +185,10 @@ namespace GUIUtil
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);
@@ -200,18 +202,46 @@ namespace GUIUtil
/* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */
QString formatTimeOffset(int64_t nTimeOffset);
+ QString formatNiceTimeOffset(qint64 secs);
+
+ class ClickableLabel : public QLabel
+ {
+ Q_OBJECT
+
+ Q_SIGNALS:
+ /** Emitted when the label is clicked. The relative mouse coordinates of the click are
+ * passed to the signal.
+ */
+ void clicked(const QPoint& point);
+ protected:
+ void mouseReleaseEvent(QMouseEvent *event);
+ };
+
+ class ClickableProgressBar : public QProgressBar
+ {
+ Q_OBJECT
+
+ Q_SIGNALS:
+ /** Emitted when the progressbar is clicked. The relative mouse coordinates of the click are
+ * passed to the signal.
+ */
+ void clicked(const QPoint& point);
+ protected:
+ void mouseReleaseEvent(QMouseEvent *event);
+ };
+
#if defined(Q_OS_MAC) && QT_VERSION >= 0x050000
// workaround for Qt OSX Bug:
// https://bugreports.qt-project.org/browse/QTBUG-15631
// QProgressBar uses around 10% CPU even when app is in background
- class ProgressBar : public QProgressBar
+ class ProgressBar : public ClickableProgressBar
{
bool event(QEvent *e) {
return (e->type() != QEvent::StyleAnimationUpdate) ? QProgressBar::event(e) : false;
}
};
#else
- typedef QProgressBar ProgressBar;
+ typedef ClickableProgressBar ProgressBar;
#endif
} // namespace GUIUtil
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 6d6af54290..2460a59109 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -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,7 +22,7 @@
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 = 120;
/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */
static const uint64_t CHAIN_STATE_SIZE = 2;
/* Total required space (in GB) depending on user choice (prune, not prune) */
@@ -63,14 +62,13 @@ private:
#include "intro.moc"
-FreespaceChecker::FreespaceChecker(Intro *intro)
+FreespaceChecker::FreespaceChecker(Intro *_intro)
{
- this->intro = intro;
+ this->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)));
+
+ 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, 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();
}
@@ -165,20 +186,19 @@ QString Intro::getDefaultDataDirectory()
return GUIUtil::boostPathToQString(GetDefaultDataDir());
}
-void Intro::pickDataDirectory()
+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())
- return;
+ 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))
+ if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || GetBoolArg("-resetguisettings", false))
{
/* If current default data directory does not exist, let the user choose one */
Intro intro;
@@ -190,7 +210,7 @@ void Intro::pickDataDirectory()
if(!intro.exec())
{
/* Cancel clicked */
- exit(0);
+ return false;
}
dataDir = intro.getDataDirectory();
try {
@@ -204,6 +224,7 @@ void Intro::pickDataDirectory()
}
settings.setValue("strDataDir", dataDir);
+ settings.setValue("fReset", false);
}
/* Only override -datadir if different from the default, to make it possible to
* override -datadir in the bitcoin.conf file in the default data directory
@@ -211,6 +232,7 @@ void Intro::pickDataDirectory()
*/
if(dataDir != getDefaultDataDirectory())
SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
+ return true;
}
void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
diff --git a/src/qt/intro.h b/src/qt/intro.h
index 9e2e96dc9e..5b428b379c 100644
--- a/src/qt/intro.h
+++ b/src/qt/intro.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -35,10 +35,13 @@ public:
/**
* Determine data directory. Let the user choose if the current one doesn't exist.
*
+ * @returns true if a data directory was selected, false if the user cancelled the selection
+ * dialog.
+ *
* @note do NOT call global GetDataDir() before calling this function, this
* will cause the wrong path to be cached.
*/
- static void pickDataDirectory();
+ static bool pickDataDirectory();
/**
* Determine default data directory for operating system.
diff --git a/src/qt/locale/bitcoin_af.ts b/src/qt/locale/bitcoin_af.ts
index 97ada8dd5c..9726987b63 100644
--- a/src/qt/locale/bitcoin_af.ts
+++ b/src/qt/locale/bitcoin_af.ts
@@ -22,6 +22,10 @@
<translation>&amp;Dupliseer</translation>
</message>
<message>
+ <source>C&amp;lose</source>
+ <translation>S&amp;luit</translation>
+ </message>
+ <message>
<source>Delete the currently selected address from the list</source>
<translation>Verwyder die adres wat u gekies het van die lys</translation>
</message>
@@ -37,6 +41,73 @@
<source>&amp;Delete</source>
<translation>&amp;Vee uit</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Kies die adres waarheen u munte wil stuur</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Kies die adres wat die munte moet ontvang</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>K&amp;ies</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Stuurders adresse</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Ontvanger adresse</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>Hierdie is die adresse vanwaar u Bitcoin betalings stuur. U moet altyd die bedrag en die adres van die ontvanger nagaan voordat u enige munte stuur.</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>Hierdie is die adresse waar u Bitcoins sal ontvang. Ons beveel aan dat u 'n nuwe adres kies vir elke transaksie</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Dupliseer Adres</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Verander</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Voer adreslys uit</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Comma separated file (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Uitvoer was onsuksesvol</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Die adreslys kon nie in %1 gestoor word nie. Probeer asseblief weer.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Merk</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen etiket)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -56,6 +127,82 @@
<source>Repeat new passphrase</source>
<translation>Herhaal nuwe wagwoord</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>Tik die nuwe wagwoord vir u beursie.&lt;br/&gt;Gerbuik asseblief 'n wagwoord met &lt;b&gt;tien of meer lukrake karakters&lt;/b&gt;, of &lt;b&gt;agt of meer woorde&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Kodifiseer beursie</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>U het u beursie se wagwoord nodig om toegang tot u beursie te verkry.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Sluit beursie oop</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>U het u beursie se wagwoord nodig om u beursie se kode te ontsyfer.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Ontsleutel beursie</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Verander wagwoord</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Tik die ou en die nuwe wagwoorde vir die beursie.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Bevestig dat die beursie gekodifiseer is</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>Waarskuwing: Indien u die beursie kodifiseer en u vergeet u wagwoord &lt;b&gt;VERLOOR U AL U BITCOINS&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Is u seker dat u die beursie wil kodifiseer?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Beursie gekodifiseer</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>BELANGRIK: Alle vorige kopieë en rugsteun-weergawes wat u tevore van die gemaak het, moet vervang word met die jongste weergawe van u nuutste gekodifiseerde beursie. Alle vorige weergawes en rugsteun-kopieë van u beursie sal nutteloos raak die oomblik wat u die nuut-gekodifiseerde beursie begin gebruik.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Kodifikasie was onsuksesvol</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Weens 'n interne fout het kodifikasie het nie geslaag nie. U beursie is nie gekodifiseer nie</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Die wagwoorde stem nie ooreen nie.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Die beursie is nie oopgesluit nie</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>U het die verkeerde wagwoord ingetik.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>WAARSKUWING: Outomatiese Kapitalisering is aktief op u sleutelbord!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -87,14 +234,42 @@
<translation>&amp;Transaksies</translation>
</message>
<message>
+ <source>Browse transaction history</source>
+ <translation>Blaai deur transaksiegeskiedenis</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation>&amp;Sluit</translation>
+ </message>
+ <message>
<source>Quit application</source>
<translation>Stop en verlaat die applikasie</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>&amp;Oor %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Wys inligting oor %1</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation>Oor &amp;Qt</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>Wys inligting oor Qt</translation>
+ </message>
+ <message>
<source>&amp;Options...</source>
<translation>&amp;Opsies</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Verander konfigurasie-opsies vir %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Kodifiseer Beursie</translation>
</message>
@@ -151,6 +326,10 @@
<translation>&amp;Ontvang</translation>
</message>
<message>
+ <source>&amp;Show / Hide</source>
+ <translation>&amp;Wys / Versteek</translation>
+ </message>
+ <message>
<source>Show or hide the main Window</source>
<translation>Wys of versteek die hoofbladsy</translation>
</message>
@@ -167,10 +346,18 @@
<translation>Verifieër boodskappe om seker te maak dat dit met die gespesifiseerde Bitcoin adresse</translation>
</message>
<message>
+ <source>&amp;File</source>
+ <translation>&amp;Leër</translation>
+ </message>
+ <message>
<source>&amp;Help</source>
<translation>&amp;Help</translation>
</message>
<message>
+ <source>Tabs toolbar</source>
+ <translation>Orebalk</translation>
+ </message>
+ <message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation>Versoek betalings (genereer QR-kodes en bitcoin: URI's)</translation>
</message>
@@ -186,53 +373,455 @@
<source>Open a bitcoin: URI or payment request</source>
<translation>Skep 'n bitcoin: URI of betalingsversoek</translation>
</message>
+ <message>
+ <source>Indexing blocks on disk...</source>
+ <translation>Blokke op skyf word geïndekseer...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk...</source>
+ <translation>Blokke op skyf word geprosesseer...</translation>
+ </message>
+ <message>
+ <source>%1 behind</source>
+ <translation>%1 agter</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation>Laaste ontvange blok is %1 gelede gegenereer.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation>Transaksies hierna sal nog nie sigbaar wees nie.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Fout</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Waarskuwing</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Inligting</translation>
+ </message>
+ <message>
+ <source>Up to date</source>
+ <translation>Op datum</translation>
+ </message>
+ <message>
+ <source>Catching up...</source>
+ <translation>Word op datum gebring...</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation>Datum: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Adres: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation>Gestuurde transaksie</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation>Inkomende transaksie</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
+ <message>
+ <source>Bytes:</source>
+ <translation>Grepe:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Fooi:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Stof:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Na Fooi:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation>(de)selekteer alle</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation>Lysmodus</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation>Bevestigings</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Bevestig</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen etiket)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation>Wysig Adres</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
+ <message>
+ <source>name</source>
+ <translation>naam</translation>
+ </message>
</context>
<context>
<name>HelpMessageDialog</name>
- </context>
+ <message>
+ <source>version</source>
+ <translation>weergawe</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation>Ongeveer %1</translation>
+ </message>
+ <message>
+ <source>UI Options:</source>
+ <translation>Gebruikerkoppelvlakopsies:</translation>
+ </message>
+ <message>
+ <source>Start minimized</source>
+ <translation>Begin geminimeer</translation>
+ </message>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Alle instellings wat in die grafiese gebruikerkoppelvlak gewysig is, terugstel</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
+ <message>
+ <source>Welcome</source>
+ <translation>Welkom</translation>
+ </message>
+ <message>
+ <source>Welcome to %1.</source>
+ <translation>Welkom by %1.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Fout</translation>
+ </message>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Hide</source>
+ <translation>Versteek</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
</context>
<context>
<name>OptionsDialog</name>
+ <message>
+ <source>Options</source>
+ <translation>Opsies</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <translation>MG</translation>
+ </message>
+ <message>
+ <source>Accept connections from outside</source>
+ <translation>Verbindings van buite toelaat</translation>
+ </message>
+ <message>
+ <source>Allow incoming connections</source>
+ <translation>Inkomende verbindings toelaat</translation>
+ </message>
+ <message>
+ <source>Reset all client options to default.</source>
+ <translation>Alle kliëntopsies na verstek terugstel.</translation>
+ </message>
+ <message>
+ <source>Expert</source>
+ <translation>Kenner</translation>
+ </message>
+ <message>
+ <source>IPv6</source>
+ <translation>IPv6</translation>
+ </message>
+ <message>
+ <source>Tor</source>
+ <translation>Tor</translation>
+ </message>
+ <message>
+ <source>default</source>
+ <translation>verstek</translation>
+ </message>
+ <message>
+ <source>none</source>
+ <translation>geen</translation>
+ </message>
+ <message>
+ <source>Confirm options reset</source>
+ <translation>Bevestig terugstel van opsies</translation>
+ </message>
+ <message>
+ <source>Client restart required to activate changes.</source>
+ <translation>Kliënt moet herbegin word om veranderinge te aktiveer.</translation>
+ </message>
</context>
<context>
<name>OverviewPage</name>
+ <message>
+ <source>Available:</source>
+ <translation>Beskikbaar:</translation>
+ </message>
+ <message>
+ <source>Pending:</source>
+ <translation>Hangend:</translation>
+ </message>
+ <message>
+ <source>Immature:</source>
+ <translation>Onvolwasse:</translation>
+ </message>
+ <message>
+ <source>Balances</source>
+ <translation>Balanse</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation>Totaal:</translation>
+ </message>
+ <message>
+ <source>Your current total balance</source>
+ <translation>U huidige totale balans</translation>
+ </message>
+ <message>
+ <source>Spendable:</source>
+ <translation>Besteebaar:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation>Onlangse transaksies</translation>
+ </message>
+ </context>
+<context>
+ <name>PaymentServer</name>
</context>
<context>
<name>PeerTableModel</name>
+ <message>
+ <source>User Agent</source>
+ <translation>Gebruikeragent</translation>
+ </message>
</context>
<context>
<name>QObject</name>
+ <message>
+ <source>%1 d</source>
+ <translation>%1 d</translation>
+ </message>
+ <message>
+ <source>%1 h</source>
+ <translation>%1 u</translation>
+ </message>
+ <message>
+ <source>%1 m</source>
+ <translation>%1 m</translation>
+ </message>
+ <message>
+ <source>%1 s</source>
+ <translation>%1 s</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Geen</translation>
+ </message>
+ <message>
+ <source>N/A</source>
+ <translation>n.v.t.</translation>
+ </message>
+ <message>
+ <source>%1 ms</source>
+ <translation>%1 ms</translation>
+ </message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 en %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
+ <message>
+ <source>N/A</source>
+ <translation>n.v.t.</translation>
+ </message>
+ <message>
+ <source>Client version</source>
+ <translation>Kliëntweergawe</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <translation>Algemeen</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Netwerk</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Naam</translation>
+ </message>
+ <message>
+ <source>Number of connections</source>
+ <translation>Aantal verbindings</translation>
+ </message>
+ <message>
+ <source>Block chain</source>
+ <translation>Blokketting</translation>
+ </message>
+ <message>
+ <source>Current number of blocks</source>
+ <translation>Huidige aantal blokke</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation>Ontvang</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation>Gestuur</translation>
+ </message>
+ <message>
+ <source>Banned peers</source>
+ <translation>Verbanne porture</translation>
+ </message>
+ <message>
+ <source>Whitelisted</source>
+ <translation>Gewitlys</translation>
+ </message>
+ <message>
+ <source>Direction</source>
+ <translation>Rigting</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation>Weergawe</translation>
+ </message>
+ <message>
+ <source>User Agent</source>
+ <translation>Gebruikeragent</translation>
+ </message>
</context>
<context>
<name>ReceiveCoinsDialog</name>
</context>
<context>
<name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Merk</translation>
+ </message>
</context>
<context>
- <name>SendCoinsDialog</name>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Merk</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen etiket)</translation>
+ </message>
</context>
<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>Bytes:</source>
+ <translation>Grepe:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Fooi:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Na Fooi:</translation>
+ </message>
+ <message>
+ <source>Transaction Fee:</source>
+ <translation>Transaksiefooi:</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Kies...</translation>
+ </message>
+ <message>
+ <source>per kilobyte</source>
+ <translation>per kilogreep</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Versteek</translation>
+ </message>
+ <message>
+ <source>total at least</source>
+ <translation>totaal ten minste</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Stof:</translation>
+ </message>
+ <message>
+ <source>Balance:</source>
+ <translation>Balans:</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen etiket)</translation>
+ </message>
+</context>
+<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -245,20 +834,118 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Merk</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen etiket)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Comma separated file (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Bevestig</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Merk</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Uitvoer was onsuksesvol</translation>
+ </message>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Voer uit</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Voer die inligting op hierdie bladsy uit na 'n leer</translation>
+ </message>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Bitcoin Core</source>
<translation>Bitcoin Kern</translation>
</message>
<message>
+ <source>Information</source>
+ <translation>Inligting</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Waarskuwing</translation>
+ </message>
+ <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Moenie transaksies vir langer as &lt;n&gt; ure in die geheuepoel hou nie (verstek: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Insufficient funds</source>
+ <translation>Onvoldoende fondse</translation>
+ </message>
+ <message>
+ <source>Loading block index...</source>
+ <translation>Blokindeks word gelaai...</translation>
+ </message>
+ <message>
+ <source>Loading wallet...</source>
+ <translation>Beursie word gelaai...</translation>
+ </message>
+ <message>
+ <source>Rescanning...</source>
+ <translation>Word herskandeer...</translation>
+ </message>
+ <message>
+ <source>Done loading</source>
+ <translation>Klaar met laai</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Fout</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_af_ZA.ts b/src/qt/locale/bitcoin_af_ZA.ts
index e553fc7759..1679482c77 100644
--- a/src/qt/locale/bitcoin_af_ZA.ts
+++ b/src/qt/locale/bitcoin_af_ZA.ts
@@ -10,9 +10,36 @@
<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>&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>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiket</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen etiket)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -32,7 +59,71 @@
<source>Repeat new passphrase</source>
<translation>Herhaal nuwe wagfrase</translation>
</message>
-</context>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Enkripteer beursie</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Hierdie operasie benodig 'n wagwoord om die beursie oop te sluit.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Sluit beursie oop</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Hierdie operasie benodig 'n wagwoord om die beursie oop te sluit.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Sluit beursie oop</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Verander wagfrase</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Tik in die ou wagfrase en die nuwe wagfrase vir die beursie.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Bevestig beursie enkripsie.</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Die beursie is nou bewaak</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Die beursie kon nie bewaak word nie</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Beursie bewaaking het misluk as gevolg van 'n interne fout. Die beursie is nie bewaak nie!</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Die wagfrase stem nie ooreen nie</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Beursie oopsluiting het misluk</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Die wagfrase wat ingetik was om die beursie oop te sluit, was verkeerd.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Beursie dekripsie het misluk</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Die beursie se wagfrase verandering was suksesvol.</translation>
+ </message>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -129,6 +220,18 @@
<source>Date</source>
<translation>Datum</translation>
</message>
+ <message>
+ <source>Copy address</source>
+ <translation>Maak kopie van adres</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopieer bedrag</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen etiket)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -140,7 +243,27 @@
<source>&amp;Address</source>
<translation>&amp;Adres</translation>
</message>
-</context>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nuwe ontvangende adres</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nuwe stuurende adres</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Wysig ontvangende adres</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Wysig stuurende adres</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Kon nie die beursie oopsluit nie.</translation>
+ </message>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -159,6 +282,13 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -180,6 +310,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -190,6 +323,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>&amp;Information</source>
@@ -206,9 +345,48 @@
<source>&amp;Message:</source>
<translation>&amp;Boodskap:</translation>
</message>
- </context>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopieer bedrag</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Bedrag</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiket</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Boodskap</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiket</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Boodskap</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen etiket)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -240,6 +418,22 @@
<source>S&amp;end</source>
<translation>S&amp;tuur</translation>
</message>
+ <message>
+ <source>Copy amount</source>
+ <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>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -253,6 +447,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -277,12 +474,238 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Van</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>onbekend</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Na</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>eie adres</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etiket</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Krediet</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>nie aanvaar nie</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Debiet</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Transaksie fooi</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Netto bedrag</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Boodskap</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>Transaksie ID</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transaksie</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Bedrag</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>waar</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>onwaar</translation>
+ </message>
+</context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipe</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiket</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Ontvang met</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Ontvang van</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Gestuur na</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Betalings Aan/na jouself</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Gemyn</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n.v.t)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen etiket)</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Datum en tyd wat die transaksie ontvang was.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Tipe transaksie.</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Alles</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Vandag</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Hierdie week</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Hierdie maand</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Verlede maand</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Hierdie jaar</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Reeks...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Ontvang met</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Gestuur na</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Aan/na jouself</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Gemyn</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Ander</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Min bedrag</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Maak kopie van adres</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopieer bedrag</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipe</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiket</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Reeks:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>aan</translation>
+ </message>
+</context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Stuur Munstukke</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts
index af62207df2..9b865f29bf 100644
--- a/src/qt/locale/bitcoin_ar.ts
+++ b/src/qt/locale/bitcoin_ar.ts
@@ -23,7 +23,7 @@
</message>
<message>
<source>C&amp;lose</source>
- <translation>&amp;اغلاق</translation>
+ <translation>ا&amp;غلاق</translation>
</message>
<message>
<source>Delete the currently selected address from the list</source>
@@ -41,6 +41,77 @@
<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>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>هذه هي عناوين Bitcion التابعة لك من أجل إرسال الدفعات. تحقق دائما من المبلغ و عنوان المرسل المستقبل قبل إرسال العملات</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>هذه هي عناوين Bitcion التابعة لك من أجل إستقبال الدفعات. ينصح استخدام عنوان جديد من أجل كل صفقة</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>انسخ العنوان</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>نسخ &amp;الوصف</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>تعديل</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>تصدير قائمة العناوين</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>ملف مفصول بفواصل (*.csv)</translation>
+ </message>
+ <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>
+ <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>
@@ -60,6 +131,90 @@
<source>Repeat new passphrase</source>
<translation>ادخل كلمة المرور الجديدة مرة أخرى</translation>
</message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>أدخل عبارة مرور جديدة إلى المحفظة. الرجاء استخدام عبارة مرور تتكون من10 حروف عشوائية على الاقل, أو أكثر من 7 كلمات</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>تحذير: إذا قمت بتشفير محفظتك وفقدت كلمة المرور الخاص بك, ستفقد كل عملات BITCOINS الخاصة بك.</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>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>تحذير: مفتاح الحروف الكبيرة مفعل</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -111,6 +266,10 @@
<translation>الخروج من التطبيق</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>حوالي %1</translation>
+ </message>
+ <message>
<source>Show information about %1</source>
<translation>أظهر المعلومات حولة %1</translation>
</message>
@@ -127,6 +286,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>
@@ -259,20 +422,8 @@
<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>لم يتم معالجة أي كتلة سجل المعاملات</numerusform><numerusform>تم معالجة كتلة واحدة سجل المعاملات</numerusform><numerusform>تم معالجة كتلتين سجل المعاملات</numerusform><numerusform>تم معالجة %n كتل سجل المعاملات</numerusform><numerusform>تم معالجة %n كتلة سجل المعاملات</numerusform><numerusform>تم معالجة %n كتلة سجل المعاملات</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>0 ساعة</numerusform><numerusform>%n ساعة</numerusform><numerusform>%n ساعتين</numerusform><numerusform>%n ساعات</numerusform><numerusform>%n ساعة</numerusform><numerusform>%n ساعات</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 و %2</translation>
+ <source>%1 behind</source>
+ <translation>خلف %1</translation>
</message>
<message>
<source>Last received block was generated %1 ago.</source>
@@ -299,6 +450,14 @@
<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>Catching up...</source>
<translation>اللحاق بالركب ...</translation>
</message>
@@ -311,12 +470,30 @@
</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>
@@ -332,7 +509,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -352,10 +529,6 @@
<translation>القيمة :</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>افضلية :</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>رسوم :</translation>
</message>
@@ -408,8 +581,52 @@
<translation>تأكيد</translation>
</message>
<message>
- <source>Priority</source>
- <translation>أفضلية</translation>
+ <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>Copy after fee</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>(no label)</source>
+ <translation>(لا وصف)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(تغير)</translation>
</message>
</context>
<context>
@@ -434,6 +651,38 @@
<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>
+ <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>
@@ -465,6 +714,10 @@
<translation>النسخة</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>حوالي %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>خيارات سطر الأوامر</translation>
</message>
@@ -512,6 +765,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>
@@ -520,11 +781,26 @@
<translation>استخدام دليل بيانات مخصص:</translation>
</message>
<message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation>خطأ: لا يمكن تكوين دليل بيانات مخصص ل %1</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>خطأ</translation>
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>نمودج</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>إخفاء</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -538,6 +814,10 @@
<source>Select payment request file</source>
<translation>حدد ملف طلب الدفع</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>حدد ملف طلب الدفع لفتحه</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -662,13 +942,20 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>استجابة سيئة من الملقم %1</translation>
+ </message>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
<message>
<source>Amount</source>
- <translation>المبلغ</translation>
+ <translation>مبلغ</translation>
</message>
<message>
<source>%1 h</source>
@@ -682,8 +969,34 @@
<source>N/A</source>
<translation>غير معروف</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 و %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
</context>
<context>
+ <name>QRImageWidget</name>
+ <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>
<source>N/A</source>
@@ -868,6 +1181,18 @@
<source>Remove</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>
@@ -887,7 +1212,54 @@
<source>&amp;Save Image...</source>
<translation>&amp;حفظ الصورة</translation>
</message>
-</context>
+ <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>
+ <message>
+ <source>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>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -915,10 +1287,6 @@
<translation>القيمة :</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>افضلية :</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>رسوم :</translation>
</message>
@@ -960,7 +1328,7 @@
</message>
<message>
<source>Dust:</source>
- <translation>غبار</translation>
+ <translation>غبار:</translation>
</message>
<message>
<source>Clear &amp;All</source>
@@ -978,6 +1346,54 @@
<source>S&amp;end</source>
<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 change</source>
+ <translation>نسخ التعديل</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 الى %2</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>أو</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>تأكيد الإرسال Coins</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>(no label)</source>
+ <translation>(لا وصف)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1029,7 +1445,18 @@
<source>Pay To:</source>
<translation>ادفع &amp;الى :</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>
+ <message>
+ <source>Yes</source>
+ <translation>نعم</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1087,7 +1514,51 @@
<source>Verify &amp;Message</source>
<translation>تحقق &amp;الرسالة</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>Please check the signature and try again.</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>
@@ -1099,16 +1570,358 @@
<name>TrafficGraphWidget</name>
</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>%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>
+ <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>not accepted</source>
+ <translation>غير مقبولة</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>دين</translation>
+ </message>
+ <message>
+ <source>Transaction fee</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>Merchant</source>
+ <translation>تاجر</translation>
+ </message>
+ <message>
+ <source>Transaction</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>
+<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>Open until %1</source>
+ <translation>مفتوح حتى %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>غير متصل</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>يتعارض</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>لم يتم تلقى هذه الكتلة (Block) من قبل أي العقد الأخرى وربما لن تكون مقبولة!</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>Mined</translation>
+ </message>
+ <message>
+ <source>(n/a)</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>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>Mined</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>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>Edit label</source>
+ <translation>عدل الوصف</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>عرض تفاصيل المعاملة</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>ملف مفصول بفواصل (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</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>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>نجح التصدير</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>المدى:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>الى</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>إرسال Coins</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <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>Backup Failed</source>
+ <translation>فشل النسخ الاحتياطي</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>نجاح النسخ الاحتياطي</translation>
+ </message>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1119,14 +1932,14 @@
<translation>حدد مجلد المعلومات</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>قبول الاتصالات من خارج</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>جوهر البيت كوين</translation>
</message>
<message>
+ <source>The %s developers</source>
+ <translation>%s المبرمجون</translation>
+ </message>
+ <message>
<source>Error: Disk space is low!</source>
<translation>تحذير: مساحة القرص منخفضة</translation>
</message>
@@ -1159,10 +1972,6 @@
<translation>قيمة العملية صغيره جدا</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>يجب ان يكون قيمة العملية بالموجب</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>المعاملة طويلة جدا</translation>
</message>
diff --git a/src/qt/locale/bitcoin_be_BY.ts b/src/qt/locale/bitcoin_be_BY.ts
index 5894148fe0..62f2ffc9e6 100644
--- a/src/qt/locale/bitcoin_be_BY.ts
+++ b/src/qt/locale/bitcoin_be_BY.ts
@@ -41,6 +41,77 @@
<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>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>
+ <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>
@@ -60,6 +131,90 @@
<source>Repeat new passphrase</source>
<translation>Паўтарыце новую кодавую фразу</translation>
</message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>Увядзіце новы пароль для гаманца.&lt;br/&gt;Парольная фраза павинна складацца&lt;b&gt; не меньш чым з дзесяці сімвалаў&lt;/b&gt;, ці &lt;b&gt;больш чым з васьмі слоў&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>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>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>
@@ -234,38 +389,6 @@
<source>&amp;Command-line options</source>
<translation>Опцыі каманднага радка</translation>
</message>
- <message numerus="yes">
- <source>%n active connection(s) to Bitcoin network</source>
- <translation><numerusform>%n актыўнае злучэнне з сецівам Bitcoin</numerusform><numerusform>%n актыўных злучэнняў з сецівам Bitcoin</numerusform><numerusform>%n актыўных злучэнняў з сецівам Bitcoin</numerusform><numerusform>%n актыўных злучэнняў з сецівам Bitcoin</numerusform></translation>
- </message>
- <message>
- <source>No block source available...</source>
- <translation>Крыніца блокаў недасяжная...</translation>
- </message>
- <message numerus="yes">
- <source>Processed %n block(s) of transaction history.</source>
- <translation><numerusform>Апрацаваны %n блок гісторыі транзакцый.</numerusform><numerusform>Апрацавана %n блокі гісторыі транзакцый.</numerusform><numerusform>Апрацавана %n блокаў гісторыі транзакцый.</numerusform><numerusform>Апрацавана %n блокаў гісторыі транзакцый.</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n гадзіна</numerusform><numerusform>%n гадзіны</numerusform><numerusform>%n гадзін</numerusform><numerusform>%n гадзін</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n дзень</numerusform><numerusform>%n дні</numerusform><numerusform>%n дзён</numerusform><numerusform>%n дзён</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n тыдзень</numerusform><numerusform>%n тыдні</numerusform><numerusform>%n тыдняў</numerusform><numerusform>%n тыдняў</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 і %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n год</numerusform><numerusform>%n гады</numerusform><numerusform>%n гадоў</numerusform><numerusform>%n гадоў</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 таму</translation>
@@ -344,7 +467,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -360,10 +483,6 @@
<translation>Колькасць:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Прыярытэт:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Камісія:</translation>
</message>
@@ -412,10 +531,62 @@
<translation>Пацверджана</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Прыярытэт</translation>
+ <source>Copy address</source>
+ <translation>Капіяваць адрас</translation>
</message>
-</context>
+ <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>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>
<message>
@@ -430,6 +601,34 @@
<source>&amp;Address</source>
<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>
+ <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>
@@ -464,6 +663,10 @@
<source>command-line options</source>
<translation>опцыі каманднага радка</translation>
</message>
+ <message>
+ <source>Start minimized</source>
+ <translation>Стартаваць ммінімізаванай</translation>
+ </message>
</context>
<context>
<name>Intro</name>
@@ -475,15 +678,14 @@
<source>Error</source>
<translation>Памылка</translation>
</message>
- <message numerus="yes">
- <source>%n GB of free space available</source>
- <translation><numerusform>%n Гб вольнага месца даступна</numerusform><numerusform>%n Гб вольнага месца даступна</numerusform><numerusform>%n Гб вольнага месца даступна</numerusform><numerusform>%n Гб вольнага месца даступна</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>(of %n GB needed)</source>
- <translation><numerusform>(з %n Гб патрэбна)</numerusform><numerusform>(з %n Гб патрэбна)</numerusform><numerusform>(з %n Гб патрэбна)</numerusform><numerusform>(з %n Гб патрэбна)</numerusform></translation>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Форма</translation>
</message>
-</context>
+ </context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -514,6 +716,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -522,6 +727,16 @@
<source>Amount</source>
<translation>Колькасць</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 і %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -544,13 +759,56 @@
<source>&amp;Label:</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>
<source>Copy &amp;Address</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>
+ <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>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -575,10 +833,6 @@
<translation>Колькасць:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Прыярытэт:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Камісія:</translation>
</message>
@@ -602,7 +856,43 @@
<source>Confirm the send action</source>
<translation>Пацвердзіць дасыланне</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>Confirm send coins</source>
+ <translation>Пацвердзіць дасыланне манет</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Велічыня плацяжу мае быць больш за 0.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>непазначаны</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -641,8 +931,15 @@
<source>Memo:</source>
<translation>Памятка:</translation>
</message>
+ <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>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -675,16 +972,274 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/offline</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/непацверджана</translation>
+ </message>
+ <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>
+ <source>Date</source>
+ <translation>Дата</translation>
+ </message>
+ <message>
+ <source>unknown</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>Amount</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>
+<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>Confirmed (%1 confirmations)</source>
+ <translation>Пацверджана (%1 пацверджанняў)</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>(n/a)</source>
+ <translation>(n/a)</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>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>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>Edit label</source>
+ <translation>Рэдагаваць пазнаку</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Коскамі падзелены файл (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</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>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Экспартаванне няўдалае</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Прамежак:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>да</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Даслаць Манеты</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>Экспарт</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>Options:</source>
diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts
index acb60cf41c..c571698304 100644
--- a/src/qt/locale/bitcoin_bg.ts
+++ b/src/qt/locale/bitcoin_bg.ts
@@ -41,6 +41,77 @@
<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>Избери</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>&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 файл (*.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>
+ <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>
@@ -60,6 +131,90 @@
<source>Repeat new passphrase</source>
<translation>Въведете новата парола повторно</translation>
</message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>Въведете новата парола към портфейла.&lt;br/&gt;Моля ползвайте парола съставена от &lt;b&gt;десет или повече произволни символа&lt;/b&gt;, или &lt;b&gt;осем или повече думи&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>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>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>
@@ -258,10 +413,6 @@
<source>&amp;Command-line options</source>
<translation>&amp;Налични команди</translation>
</message>
- <message numerus="yes">
- <source>%n active connection(s) to Bitcoin network</source>
- <translation><numerusform>%n активна връзка към Биткойн мрежата</numerusform><numerusform>%n активни връзки към Биткойн мрежата</numerusform></translation>
- </message>
<message>
<source>Indexing blocks on disk...</source>
<translation>Индексиране на блокове на диска...</translation>
@@ -271,34 +422,6 @@
<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></translation>
- </message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n час</numerusform><numerusform>%n часа</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n ден</numerusform><numerusform>%n дни</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><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></translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 зад</translation>
</message>
@@ -384,7 +507,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -404,10 +527,6 @@
<translation>Сума:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Приоритет:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Такса:</translation>
</message>
@@ -460,8 +579,76 @@
<translation>Потвърдени</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Приоритет</translation>
+ <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>(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>
@@ -486,6 +673,38 @@
<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>
+ <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>
@@ -587,15 +806,22 @@
<source>Error</source>
<translation>Грешка</translation>
</message>
- <message numerus="yes">
- <source>%n GB of free space available</source>
- <translation><numerusform>%n GB свободно пространство на разположение</numerusform><numerusform>%n GB свободно пространство на разположение</numerusform></translation>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Формуляр</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Време на последния блок</translation>
</message>
- <message numerus="yes">
- <source>(of %n GB needed)</source>
- <translation><numerusform>(%n GB е нужен)</numerusform><numerusform>(%n GB са нужни)</numerusform></translation>
+ <message>
+ <source>Hide</source>
+ <translation>Скрий</translation>
</message>
-</context>
+ </context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -830,17 +1056,80 @@
</message>
</context>
<context>
- <name>PeerTableModel</name>
+ <name>PaymentServer</name>
<message>
- <source>User Agent</source>
- <translation>Клиент на потребителя</translation>
+ <source>Payment request error</source>
+ <translation>Възникна грешка по време назаявката за плащане</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Време за отговор</translation>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Биткойн не можe да се стартира: click-to-pay handler</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Справяне с URI</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Невалиден адрес на плащане %1</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</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>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>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>
+ <source>User Agent</source>
+ <translation>Клиент на потребителя</translation>
+ </message>
+ </context>
+<context>
<name>QObject</name>
<message>
<source>Amount</source>
@@ -878,6 +1167,32 @@
<source>%1 ms</source>
<translation>%1 милисекунда</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 и %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ <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>
@@ -1112,6 +1427,18 @@
<source>Remove</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>
@@ -1131,8 +1458,59 @@
<source>&amp;Save Image...</source>
<translation>&amp;Запиши изображение...</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Изискване на плащане от %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Данни за плащането</translation>
+ </message>
+ <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>Error encoding URI into QR Code.</source>
+ <translation>Грешка при създаването на QR Code от URI.</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>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -1163,10 +1541,6 @@
<translation>Сума:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Приоритет:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Такса:</translation>
</message>
@@ -1211,10 +1585,6 @@
<translation>По избор:</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Време за потвърждение:</translation>
- </message>
- <message>
<source>normal</source>
<translation>нормален</translation>
</message>
@@ -1254,6 +1624,82 @@
<source>S&amp;end</source>
<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>or</source>
+ <translation>или</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</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>Transaction creation failed!</source>
+ <translation>Грешка при създаването на транзакция!</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Заявката за плащане е изтекла.</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Внимание: Невалиден Биткойн адрес</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Внимание:Неизвестен адрес за промяна</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(без име)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1305,6 +1751,17 @@
<source>Memo:</source>
<translation>Бележка:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Въведете име за този адрес, за да го добавите в списъка с адреси</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Да</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1375,7 +1832,59 @@
<source>Verify &amp;Message</source>
<translation>Потвърди &amp;съобщението</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>
@@ -1391,16 +1900,434 @@
</message>
</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>%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>
+ <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>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>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>Amount</source>
+ <translation>Сума</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>true</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>false</translation>
+ </message>
+</context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Описание на транзакцията</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>Open until %1</source>
+ <translation>Подлежи на промяна до %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Извън линия</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</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>watch-only</source>
+ <translation>само гледане</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/a)</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>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>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>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 файл (*.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>
+ <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>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Няма зареден портфейл.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Изпращане</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>Изнеси</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>
<source>Options:</source>
@@ -1419,18 +2346,10 @@
<translation>Въведете Ваш публичен адрес</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Приемайте връзки отвън.(по подразбиране:1 в противен случай -proxy или -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Биткойн ядро</translation>
</message>
<message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Сложете в бял списък пиъри,свързващи се от дадената интернет маска или айпи адрес.Може да бъде заложено неколкократно.</translation>
- </message>
- <message>
<source>&lt;category&gt; can be:</source>
<translation>&lt;category&gt; може да бъде:</translation>
</message>
@@ -1491,10 +2410,6 @@
<translation>Сумата на транзакцията е твърде малка</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Сумите на транзакциите трябва да са положителни</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>Транзакцията е твърде голяма</translation>
</message>
diff --git a/src/qt/locale/bitcoin_bg_BG.ts b/src/qt/locale/bitcoin_bg_BG.ts
index 4bddb5ff4a..d982da4dd8 100644
--- a/src/qt/locale/bitcoin_bg_BG.ts
+++ b/src/qt/locale/bitcoin_bg_BG.ts
@@ -41,6 +41,77 @@
<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>Comma separated file (*.csv)</source>
+ <translation>Comma separated file (*.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>
+ <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>
@@ -60,7 +131,35 @@
<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>Confirm wallet encryption</source>
+ <translation>Потвърди криптирането на порфейла</translation>
+ </message>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -165,6 +264,10 @@
</context>
<context>
<name>CoinControlDialog</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(без етикет)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -179,6 +282,9 @@
<name>Intro</name>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -188,12 +294,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -201,14 +316,40 @@
</context>
<context>
<name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>Адрес</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Етикет</translation>
+ </message>
</context>
<context>
- <name>SendCoinsDialog</name>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Етикет</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(без етикет)</translation>
+ </message>
</context>
<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(без етикет)</translation>
+ </message>
+</context>
+<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -221,12 +362,62 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</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>Comma separated file (*.csv)</source>
+ <translation>Comma separated file (*.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>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>Изнеси</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>Bitcoin Core</source>
diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts
index ed259c4d08..84f51d18a8 100644
--- a/src/qt/locale/bitcoin_ca.ts
+++ b/src/qt/locale/bitcoin_ca.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Elimina</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Trieu l'adreça on enviar les monedes</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Trieu l'adreça on rebre les monedes</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Tria</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Adreces d'enviament</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Adreces de recepció</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>Aquestes són les vostres adreces de Bitcoin per enviar els pagaments. Sempre reviseu l'import i l'adreça del destinatari abans de transferir monedes.</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>Aquestes són les vostres adreces Bitcoin per rebre pagaments. Es recomana utilitzar una adreça nova de recepció per a cada transacció.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Copia l'adreça</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copia l'eti&amp;queta</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Edita</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exporta la llista d'adreces</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Fitxer separat per comes (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>L'exportació ha fallat</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>S'ha produït un error en desar la llista d'adreces a %1. Torneu-ho a provar.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreça</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>Repetiu la nova contrasenya</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>Introduïu la contrasenya nova al moneder.&lt;br/&gt;Utilitzeu una contrasenya de &lt;b&gt;deu o més caràcters aleatoris&lt;/b&gt;, o &lt;b&gt;vuit o més paraules&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Encripta el moneder</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Aquesta operació requereix la contrasenya del moneder per a desbloquejar-lo.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Desbloqueja el moneder</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Aquesta operació requereix la contrasenya del moneder per desencriptar-lo.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Desencripta el moneder</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Canvia la contrasenya</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Introduïu la contrasenya antiga i la contrasenya nova al moneder.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Confirma l'encriptació del moneder</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>Avís: si encripteu el vostre moneder i perdeu la contrasenya, &lt;b&gt;PERDREU TOTS ELS VOSTRES BITCOINS&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Esteu segur que voleu encriptar el vostre moneder?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Moneder encriptat</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>Ara es tancarà el %1 per finalitzar el procés d'encriptació. Recordeu que encriptar el vostre moneder no garanteix que les vostres bitcoins no puguin ser robades per programari maliciós que infecti l'ordinador.</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>IMPORTANT: Tota copia de seguretat que hàgiu realitzat hauria de ser reemplaçada pel, recentment generat, fitxer encriptat del moneder. Per motius de seguretat, les còpies de seguretat anteriors del fitxer de moneder no encriptat esdevindran inusables tan aviat com començar a utilitzar el nou moneder encriptat.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>L'encriptació del moneder ha fallat</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>L'encriptació del moneder ha fallat per un error intern. El moneder no ha estat encriptat.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Les contrasenyes introduïdes no coincideixen.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>El desbloqueig del moneder ha fallat</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>La contrasenya introduïda per a desencriptar el moneder és incorrecta.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>La desencriptació del moneder ha fallat</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>La contrasenya del moneder ha estat modificada correctament.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Avís: Les lletres majúscules estan activades!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -111,6 +270,14 @@
<translation>Surt de l'aplicació</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>Qu&amp;ant al %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Mosta informació sobre el %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>Quant a &amp;Qt</translation>
</message>
@@ -123,6 +290,10 @@
<translation>&amp;Opcions...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Modifica les opcions de configuració de %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Encripta el moneder...</translation>
</message>
@@ -140,13 +311,25 @@
</message>
<message>
<source>&amp;Receiving addresses...</source>
- <translation>Adreces de &amp;recepció</translation>
+ <translation>Adreces de &amp;recepció...</translation>
</message>
<message>
<source>Open &amp;URI...</source>
<translation>Obre un &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Feu clic per inhabilitar l'activitat de la xarxa.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>S'ha inhabilitat l'activitat de la xarxa.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Feu clic per tornar a habilitar l'activitat de la xarxa.</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>S'estan reindexant els blocs al disc...</translation>
</message>
@@ -251,32 +434,16 @@
<translation><numerusform>%n connexió activa a la xarxa Bitcoin</numerusform><numerusform>%n connexions actives a la xarxa Bitcoin</numerusform></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'han processat %n bloc de l'historial de transacció.</numerusform><numerusform>S'han processat %n blocs de l'historial de transacció.</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n hora</numerusform><numerusform>%n hores</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n dia</numerusform><numerusform>%n dies</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n setmana</numerusform><numerusform>%n setmanes</numerusform></translation>
+ <source>Indexing blocks on disk...</source>
+ <translation>S'estan indexant els blocs al disc...</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 i %2</translation>
+ <source>Processing blocks on disk...</source>
+ <translation>S'estan processant els blocs al disc...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n any</numerusform><numerusform>%n anys</numerusform></translation>
+ <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>
</message>
<message>
<source>%1 behind</source>
@@ -307,6 +474,14 @@
<translation>Al dia</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Mostra el missatge d'ajuda del %1 per obtenir una llista amb les possibles opcions de línia d'ordres de Bitcoin</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>Client de %1</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>S'està posant al dia ...</translation>
</message>
@@ -349,6 +524,14 @@
<translation>Transacció entrant</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>La generació de la clau HD és &lt;b&gt;habilitada&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>La generació de la clau HD és &lt;b&gt;inhabilitada&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>El moneder està &lt;b&gt;encriptat&lt;/b&gt; i actualment &lt;b&gt;desbloquejat&lt;/b&gt;</translation>
</message>
@@ -356,6 +539,10 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>El moneder està &lt;b&gt;encriptat&lt;/b&gt; i actualment &lt;b&gt;bloquejat&lt;/b&gt;</translation>
</message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>S'ha produït un error fatal. Bitcoin no pot continuar amb seguretat i finalitzarà.</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -376,12 +563,8 @@
<translation>Import:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritat:</translation>
- </message>
- <message>
<source>Fee:</source>
- <translation>Comissió</translation>
+ <translation>Comissió:</translation>
</message>
<message>
<source>Dust:</source>
@@ -432,8 +615,84 @@
<translation>Confirmat</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Prioritat</translation>
+ <source>Copy address</source>
+ <translation>Copia l'adreça</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copia l'etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copia l'ID de transacció</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Bloqueja sense gastar</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Desbloqueja sense gastar</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copia la quantitat</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copia la comissió</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copia la comissió posterior</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copia els bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copia el polsim</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copia el canvi</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 bloquejada)</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>Aquesta etiqueta es torna vermella si cap recipient rep un import inferior al llindar de polsim actual.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Pot variar en +/- %1 satoshi(s) per entrada.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>canvia de %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(canvia)</translation>
</message>
</context>
<context>
@@ -458,6 +717,38 @@
<source>&amp;Address</source>
<translation>&amp;Adreça</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nova adreça de recepció</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nova adreça d'enviament</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Edita l'adreça de recepció</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Edita l'adreça d'enviament</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>L'adreça introduïda «%1» no és una adreça de Bitcoin vàlida.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>L'adreça introduïda «%1» ja és present a la llibreta d'adreces.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>No s'ha pogut desbloquejar el moneder.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Ha fallat la generació d'una clau nova.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -493,6 +784,10 @@
<translation>(%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>Quant al %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Opcions de línia d'ordres</translation>
</message>
@@ -528,12 +823,28 @@
<source>Show splash screen on startup (default: %u)</source>
<translation>Mostra la pantalla de benvinguda a l'inici (per defecte: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Reinicialitza tots els canvis de configuració fets des de la interfície gràfica</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
<source>Welcome</source>
- <translation>Us donem la benviguda</translation>
+ <translation>Us donem la benvinguda</translation>
+ </message>
+ <message>
+ <source>Welcome to %1.</source>
+ <translation>Us donem la benvinguda a %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>Com és la primera vegada que s'executa el programa, podeu triar on %1 emmagatzemarà les dades.</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>%1 baixarà i emmagatzemarà una còpia de la cadena de blocs de Bitcoin. Com a mínim %2GB de dades s'emmagatzemaran en aquest directori, i augmentarà al llarg del temps. El moneder també s'emmagatzemarà en aquest directori.</translation>
</message>
<message>
<source>Use the default data directory</source>
@@ -561,6 +872,37 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulari</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Últim temps de bloc</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>Progrés</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>s'està calculant...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Temps estimat restant fins sincronitzat</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Amaga</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Desconegut. Sincronització de les capçaleres (%1)...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -578,6 +920,10 @@
<source>Select payment request file</source>
<translation>Selecciona un fitxer de sol·licitud de pagament</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Seleccioneu el fitxer de sol·licitud de pagament per obrir</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -590,6 +936,14 @@
<translation>&amp;Principal</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>Inicieu %1 automàticament després d'entrar en el sistema.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>&amp;Inicia %1 en l'entrada al sistema</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>Mida de la memòria cau de la base de &amp;dades</translation>
</message>
@@ -726,6 +1080,14 @@
<translation>&amp;Finestra</translation>
</message>
<message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>Ama&amp;ga la icona de la safata del sistema.</translation>
+ </message>
+ <message>
+ <source>Hide tray icon</source>
+ <translation>Amaga la icona de la safata</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation>Mostra només la icona de la barra en minimitzar la finestra.</translation>
</message>
@@ -746,6 +1108,10 @@
<translation>&amp;Llengua de la interfície d'usuari:</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>Aquí es pot definir la llengua de la interfície d'usuari. Aquest paràmetre tindrà efecte en reiniciar el %1.</translation>
+ </message>
+ <message>
<source>&amp;Unit to show amounts in:</source>
<translation>&amp;Unitats per mostrar els imports en:</translation>
</message>
@@ -870,6 +1236,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Error de la sol·licitud de pagament</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>No es pot iniciar bitcoin: controlador click-to-pay</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Gestió d'URI</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>L'URL de recuperació de la sol·licitud de pagament no és vàlida: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Adreça de pagament no vàlida %1</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation>L'URI no pot ser analitzat! Això pot ser a causa d'una adreça de Bitcoin no vàlida o per paràmetres URI amb mal format.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Gestió de fitxers de les sol·licituds de pagament</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>No es pot llegir el fitxer de la sol·licitud de pagament. Això pot ser causat per un fitxer de sol·licitud de pagament no vàlid.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>La sol·licitud de pagament s'ha rebutjat</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>La xarxa de la sol·licitud de pagament no coincideix amb la xarxa del client.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>La sol·licitud de pagament ha vençut.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>La sol·licitud de pagament no està inicialitzada.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>No s'accepten sol·licituds de pagament no verificades a scripts de pagament personalitzats.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Sol·licitud de pagament no vàlida.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>L'import de pagament sol·licitat %1 és massa petit (es considera polsim).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Reemborsament de %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>La sol·licitud de pagament %1 és massa gran (%2 bytes, permès %3 bytes).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Error en comunicar amb %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>No es pot analitzar la sol·licitud de pagament!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Mala resposta del servidor %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Error en la sol·licitud de xarxa</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Pagament reconegut</translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -879,11 +1336,7 @@
<source>Node/Service</source>
<translation>Node/Servei</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Temps de ping</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -922,6 +1375,32 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 i %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>De&amp;sa la imatge...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Copia la imatge</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Desa el codi QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Imatge PNG (*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -950,6 +1429,10 @@
<translation>Utilitzant BerkeleyDB versió</translation>
</message>
<message>
+ <source>Datadir</source>
+ <translation>Datadir</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>&amp;Temps d'inici</translation>
</message>
@@ -1110,14 +1593,6 @@
<translation>Neteja la consola</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Desconnecta el node</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Bandeja el node durant</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;hora</translation>
</message>
@@ -1134,10 +1609,6 @@
<translation>1 &amp;any</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Desbandeja el node</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>Utilitza les fletxes d'amunt i avall per navegar per l'historial, i &lt;b&gt;Ctrl-L&lt;\b&gt; per netejar la pantalla.</translation>
</message>
@@ -1264,6 +1735,18 @@
<source>Remove</source>
<translation>Esborra</translation>
</message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copia l'etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Copia el missatge</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1283,6 +1766,73 @@
<source>&amp;Save Image...</source>
<translation>De&amp;sa la imatge...</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Sol·licita un pagament a %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informació de pagament</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreça</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Import</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Missatge</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>URI resultant massa llarga, intenta reduir el text per a la etiqueta / missatge</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Error en codificar l'URI en un codi 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>Missatge</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(sense missatge)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(no s'ha sol·licitat import)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Sol·licitat</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1319,10 +1869,6 @@
<translation>Import:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritat:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Comissió:</translation>
</message>
@@ -1391,10 +1937,6 @@
<translation>(No s'ha inicialitzat encara la comissió intel·ligent. Normalment pren uns pocs blocs...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Temps de confirmació:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1412,7 +1954,7 @@
</message>
<message>
<source>Clear all fields of the form.</source>
- <translation>Netejar tots els camps del formulari.</translation>
+ <translation>Esborra tots els camps del formuari.</translation>
</message>
<message>
<source>Dust:</source>
@@ -1434,6 +1976,106 @@
<source>S&amp;end</source>
<translation>E&amp;nvia</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copia la quantitat</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copia la comissió</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copia la comissió posterior</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copia els bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copia el polsim</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copia el canvi</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>Esteu segur que ho voleu enviar?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>S'ha afegit una taxa de transacció</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Import total %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>o</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Confirma l'enviament de monedes</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>L'adreça del destinatari no és vàlida. Torneu-la a comprovar.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>L'import a pagar ha de ser major que 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>L'import supera el vostre balanç.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>El total excedeix el vostre balanç quan s'afegeix la comissió a la transacció %1.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>S'ha trobat una adreça duplicada: les adreces només s'haurien d'utilitzar una vegada cada una.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>La creació de la transacció ha fallat!</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Una comissió superior a %1 es considera una comissió absurdament alta.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>La sol·licitud de pagament ha vençut.</translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Paga només la comissió necessària de %1</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Avís: adreça Bitcoin no vàlida</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Avís: adreça de canvi desconeguda</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1451,7 +2093,7 @@
</message>
<message>
<source>Choose previously used address</source>
- <translation>Escull una adreça feta servir anteriorment</translation>
+ <translation>Tria les adreces fetes servir amb anterioritat</translation>
</message>
<message>
<source>This is a normal payment.</source>
@@ -1513,6 +2155,17 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Introduïu una etiqueta per a aquesta adreça per afegir-la a la llibreta d'adreces</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Sí</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1545,11 +2198,11 @@
</message>
<message>
<source>Alt+A</source>
- <translation>Alt+A</translation>
+ <translation>Alta+A</translation>
</message>
<message>
<source>Paste address from clipboard</source>
- <translation>Enganxa l'adreça del porta-retalls</translation>
+ <translation>Enganxar adreça del porta-retalls</translation>
</message>
<message>
<source>Alt+P</source>
@@ -1607,6 +2260,58 @@
<source>Reset all verify message fields</source>
<translation>Neteja tots els camps de verificació de missatge</translation>
</message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Feu clic a «Signa el missatge» per a generar una signatura</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>L'adreça introduïda no és vàlida.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Comproveu l'adreça i torneu-ho a provar.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>L'adreça introduïda no referencia a cap clau.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>El desbloqueig del moneder ha estat cancelat.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>La clau privada per a la adreça introduïda no està disponible.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>La signatura del missatge ha fallat.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Missatge signat.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>La signatura no s'ha pogut descodificar.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Comproveu la signatura i torneu-ho a provar.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>La signatura no coincideix amb el resum del missatge.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Ha fallat la verificació del missatge.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Missatge verificat.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1623,11 +2328,404 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Open until %1</source>
+ <translation>Obert fins %1</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/fora de línia</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/sense confirmar</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 confirmacions</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Estat</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, encara no ha estat emès correctement</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Font</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Generada</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>De</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconegut</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>adreça pròpia</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>només lectura</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etiqueta</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Crèdit</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>no acceptat</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>Transaction fee</source>
+ <translation>Comissió de transacció</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Import net</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Missatge</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Comentari</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>ID de la transacció</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Mercader</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>Les monedes generades han de madurar %1 blocs abans de poder ser gastades. Quan genereu aquest bloc, es farà saber a la xarxa per tal d'afegir-lo a la cadena de blocs. Si no pot fer-se lloc a la cadena, el seu estat canviarà a «no acceptat» i no es podrà gastar. Això pot passar ocasionalment si un altre node genera un bloc en un marge de segons respecte al vostre.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Informació de depuració</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transacció</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Entrades</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Import</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>cert</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>fals</translation>
+ </message>
+</context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Aquest panell mostra una descripció detallada de la transacció</translation>
</message>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipus</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Obert fins %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Fora de línia</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Sense confirmar</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Abandonada</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Confirmant (%1 de %2 confirmacions recomanades)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Confirmat (%1 confirmacions)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>En conflicte</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Immadur (%1 confirmacions, serà disponible després de %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Aquest bloc no ha estat rebut per cap altre node i probablement no serà acceptat!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Generat però no acceptat</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Rebuda amb</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Rebuda de</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviada a</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Pagament a un mateix</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minada</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>només lectura</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/a)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Estat de la transacció. Desplaceu-vos sobre aquest camp per mostrar el nombre de confirmacions.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Data i hora en que la transacció va ser rebuda.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Tipus de transacció.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Si està implicada o no una adreça només de lectura en la transacció.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Intenció/propòsit de la transacció definida per l'usuari.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Import extret o afegit del balanç.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Tot</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Avui</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Aquesta setmana</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Aquest mes</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>El mes passat</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Enguany</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Rang...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Rebuda amb</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviada a</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>A un mateix</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minada</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Altres</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Introduïu una adreça o una etiqueta per cercar</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Import mínim</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Copia l'adreça</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copia l'etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copia l'ID de transacció</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Copia la transacció crua</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Editar etiqueta</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Mostra detalls de la transacció</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exporta l'historial de transacció</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Fitxer separat per comes (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Confirmat</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Només de lectura</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipus</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreça</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>L'exportació ha fallat</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>S'ha produït un error en provar de desar l'historial de transacció a %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Exportació amb èxit</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>L'historial de transaccions s'ha desat correctament a %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Rang:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>a</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1637,6 +2735,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>No s'ha carregat cap moneder.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Envia monedes</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Exporta</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Exporta les dades de la pestanya actual a un fitxer</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Còpia de seguretat del moneder</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Dades del moneder (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Ha fallat la còpia de seguretat</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>S'ha produït un error en provar de desar les dades del moneder a %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>La còpia de seguretat s'ha realitzat correctament</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>S'han desat les dades del moneder correctament a %1.</translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1671,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>
@@ -1699,18 +2842,10 @@
<translation>No s'ha pogut iniciar el servidor HTTP. Vegeu debug.log per a més detalls.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Accepta connexions de fora (per defecte: 1 si no -proxy o -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee és molt elevat. Aquesta és la comissió de transacció que podeu pagar quan les estimacions de comissions no estan disponibles.</translation>
- </message>
- <message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
<translation>Vincula a una adreça específica i sempre escolta-hi. Utilitza la notació [host]:port per IPv6</translation>
</message>
@@ -1719,10 +2854,6 @@
<translation>Elimina totes les transaccions del moneder i només recupera aquelles de la cadena de blocs a través de -rescan a l'inici</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuït sota llicència de programari MIT. Vegeu el fitxer acompanyant COPYING o &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Executa una ordre quan una transacció del moneder canviï (%s en cmd es canvia per TxID)</translation>
</message>
@@ -1731,22 +2862,6 @@
<translation>Defineix el nombre de fils de verificació d'scripts (%u a %d, 0 = auto, &lt;0 = deixa tants nuclis lliures, per defecte: %d)</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>Aquesta és una versió de pre-llançament - utilitza-la sota la teva responsabilitat - No usar per a minería o aplicacions de compra-venda</translation>
- </message>
- <message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Avís: la xarxa no sembla que hi estigui plenament d'acord. Alguns miners sembla que estan experimentant problemes.</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>Avís: sembla que no estem plenament d'acord amb els nostres iguals! Podria caler que actualitzar l'aplicació, o potser que ho facin altres nodes.</translation>
- </message>
- <message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Afegeix a la llista blanca els iguals que es connecten de la màscara de xarxa o adreça IP donada. Es pot especificar moltes vegades.</translation>
- </message>
- <message>
<source>&lt;category&gt; can be:</source>
<translation>&lt;category&gt; pot ser:</translation>
</message>
@@ -1755,10 +2870,6 @@
<translation>Opcions de la creació de blocs:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Connecta només al(s) node(s) especificats</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Opcions de connexió:</translation>
</message>
@@ -1847,6 +2958,10 @@
<translation>Utilitza UPnP per a mapejar el port d'escolta (per defecte: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Utilitza la cadena de proves</translation>
+ </message>
+ <message>
<source>Verifying blocks...</source>
<translation>S'estan verificant els blocs...</translation>
</message>
@@ -1859,6 +2974,14 @@
<translation>El moneder %s resideix fora del directori de dades %s</translation>
</message>
<message>
+ <source>Wallet debugging/testing options:</source>
+ <translation>Opcions de depuració/proves del moneder:</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>Cal reescriure el moneder: reinicieu %s per a completar-ho</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Opcions de moneder:</translation>
</message>
@@ -1903,10 +3026,6 @@
<translation>Mida màxima de les dades en les transaccions de l'operador en què confiem i en les meves (per defecte: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Consulta a adreces d'iguals a través de DNS, si es troba baix en adreces (per defecte: 1 a menys que -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Genera a l'atzar credencials per a cada connexió proxy. Això habilita l'aïllament del flux de Tor (per defecte: %u)</translation>
</message>
@@ -1919,10 +3038,6 @@
<translation>L'import de la transacció és massa petit per enviar-la després que se'n dedueixi la comissió</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Aquest producte inclou programari desenvolupat pel projecte OpenSSL per a ús a l'OpenSSL Toolkit &lt;https://www.openssl.org/&gt; i programari criptogràfic escrit per Eric Young i programari UPnP escrit per Thomas Bernard.</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>Els iguals en la llista blanca no poden ser bandejats per DoS i es transmetran sempre llurs transaccions, fins i tot si ja són a la mempool. Això és útil, p. ex., per a una passarel·la</translation>
</message>
@@ -1948,7 +3063,7 @@
</message>
<message>
<source>Information</source>
- <translation>&amp;Informació</translation>
+ <translation>Informació</translation>
</message>
<message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
@@ -2007,10 +3122,6 @@
<translation>Import de la transacció massa petit</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Els imports de les transaccions han de ser positius</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transacció massa gran per a la política de comissions</translation>
</message>
@@ -2135,10 +3246,6 @@
<translation>Defineix la mida clau disponible a &lt;n&gt; (per defecte: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Defineix la mida de bloc mínima en bytes (per defecte: %u)</translation>
- </message>
- <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>Defineix el nombre de fils a crides de servei RPC (per defecte: %d)</translation>
</message>
@@ -2159,10 +3266,22 @@
<translation>Gasta el canvi no confirmat en enviar les transaccions (per defecte: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>S'estan iniciant els fils de la xarxa...</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Llindar per a desconnectar els iguals de comportament qüestionable (per defecte: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Els imports de la transacció no han de ser negatius</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>La transacció ha de tenir com a mínim un destinatari</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Xarxa desconeguda especificada a -onlynet: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ca@valencia.ts b/src/qt/locale/bitcoin_ca@valencia.ts
index df0f750a61..0123f8faab 100644
--- a/src/qt/locale/bitcoin_ca@valencia.ts
+++ b/src/qt/locale/bitcoin_ca@valencia.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Elimina</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Trieu una adreça on voleu enviar monedes</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Trieu l'adreça on voleu rebre monedes</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>T&amp;ria</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>S'estan enviant les adreces</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>S'estan rebent les adreces</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ón les vostres adreces de Bitcoin per enviar els pagaments. Sempre reviseu l'import i l'adreça del destinatari abans de transferir monedes.</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ón les vostres adreces Bitcoin per rebre pagaments. Es recomana utilitzar una adreça nova de recepció per a cada transacció.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Copia l'adreça</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copia l'&amp;etiqueta</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Edita</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exporta la llista d'adreces</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Fitxer de separació amb comes (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>L'exportació ha fallat</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>S'ha produït un error en guardar la llista d'adreces a %1. Torneu-ho a provar.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreça</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,6 +131,90 @@
<source>Repeat new passphrase</source>
<translation>Repetiu la nova contrasenya</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>Introduïu la contrasenya nova al moneder.&lt;br/&gt;Utilitzeu una contrasenya de &lt;b&gt;deu o més caràcters aleatoris&lt;/b&gt;, o &lt;b&gt;vuit o més paraules&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Encripta el moneder</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Esta operació requereix la contrasenya del moneder per a desbloquejar-lo.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Desbloqueja el moneder</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Esta operació requereix la contrasenya del moneder per desencriptar-lo.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Desencripta el moneder</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Canvia la contrasenya</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Introduïu la contrasenya antiga i la contrasenya nova al moneder.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Confirma l'encriptació del moneder</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>Avís: si encripteu el vostre moneder i perdeu la contrasenya, &lt;b&gt;PERDREU TOTS ELS VOSTRES BITCOINS&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Esteu segur que voleu encriptar el vostre moneder?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Moneder encriptat</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>IMPORTANT: Tota copia de seguretat que hàgeu realitzat hauria de ser reemplaçada pel, recentment generat, fitxer encriptat del moneder.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>L'encriptació del moneder ha fallat</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>L'encriptació del moneder ha fallat per un error intern. El moneder no ha estat encriptat.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>La contrasenya introduïda no coincideix.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>El desbloqueig del moneder ha fallat</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>La contrasenya introduïda per a desencriptar el moneder és incorrecta.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>La desencriptació del moneder ha fallat</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>La contrasenya del moneder ha estat modificada correctament.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Avís: Les lletres majúscules estan activades!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -238,38 +393,6 @@
<source>&amp;Command-line options</source>
<translation>Opcions de la &amp;línia d'ordes</translation>
</message>
- <message numerus="yes">
- <source>%n active connection(s) to Bitcoin network</source>
- <translation><numerusform>%n connexió activa a la xarxa Bitcoin</numerusform><numerusform>%n connexions actives a la xarxa Bitcoin</numerusform></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>Proccessats %n bloc de l'historial de transaccions.</numerusform><numerusform>Proccessats %n blocs de l'historial de transaccions.</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n hora</numerusform><numerusform>%n hores</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n dia</numerusform><numerusform>%n dies</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n setmana</numerusform><numerusform>%n setmanes</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 i %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n any</numerusform><numerusform>%n anys</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 darrere</translation>
@@ -348,7 +471,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>El moneder està &lt;b&gt;encriptat&lt;/b&gt; i actualment &lt;b&gt;bloquejat&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -368,10 +491,6 @@
<translation>Import:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritat:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Comissió</translation>
</message>
@@ -424,8 +543,80 @@
<translation>Confirmat</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Prioritat</translation>
+ <source>Copy address</source>
+ <translation>Copiar adreça </translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copiar ID de transacció</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Bloqueja sense gastar</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Desbloqueja sense gastar</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copia la quantitat</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copia la comissió</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copia la comissió posterior</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copia els bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copia el polsim</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copia el canvi</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 bloquejada)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>sí</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>no</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Pot variar +/- %1 satoshi(s) per entrada.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>canvia de %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(canvia)</translation>
</message>
</context>
<context>
@@ -450,6 +641,38 @@
<source>&amp;Address</source>
<translation>&amp;Adreça</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nova adreça de recepció.</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nova adreça d'enviament</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Edita les adreces de recepció</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Edita les adreces d'enviament</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>L'adreça introduïda «%1» no és una adreça de Bitcoin vàlida.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>L'adreça introduïda «%1» ja és present a la llibreta d'adreces.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>No s'ha pogut desbloquejar el moneder.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Ha fallat la generació d'una nova clau.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -496,6 +719,22 @@
<source>command-line options</source>
<translation>Opcions de la línia d'ordes</translation>
</message>
+ <message>
+ <source>UI Options:</source>
+ <translation>Opcions d'interfície:</translation>
+ </message>
+ <message>
+ <source>Set language, for example "de_DE" (default: system locale)</source>
+ <translation>Defineix un idioma, per exemple «de_DE» (per defecte: preferències locals de sistema)</translation>
+ </message>
+ <message>
+ <source>Start minimized</source>
+ <translation>Inicia minimitzat</translation>
+ </message>
+ <message>
+ <source>Set SSL root certificates for payment request (default: -system-)</source>
+ <translation>Defineix certificats arrel SSL per a la sol·licitud de pagament (per defecte: -sistema-)</translation>
+ </message>
</context>
<context>
<name>Intro</name>
@@ -519,15 +758,22 @@
<source>Error</source>
<translation>Error</translation>
</message>
- <message numerus="yes">
- <source>%n GB of free space available</source>
- <translation><numerusform>%n GB d'espai lliure disponible</numerusform><numerusform>%n GB d'espai lliure disponible</numerusform></translation>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulari</translation>
</message>
- <message numerus="yes">
- <source>(of %n GB needed)</source>
- <translation><numerusform>(de %n GB necessari)</numerusform><numerusform>(de %n GB necessaris)</numerusform></translation>
+ <message>
+ <source>Last block time</source>
+ <translation>Últim temps de bloc</translation>
</message>
-</context>
+ <message>
+ <source>Hide</source>
+ <translation>Amaga</translation>
+ </message>
+ </context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -546,6 +792,10 @@
<source>Select payment request file</source>
<translation>Selecciona un fitxer de sol·licitud de pagament</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Selecciona el fitxer de sol·licitud de pagament per obrir</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -814,6 +1064,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Error en la sol·licitud de pagament</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>No es pot iniciar bitcoin: gestor clica-per-pagar</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Gestió d'URI</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>L'URL de recuperació de la sol·licitud de pagament no és vàlida: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Adreça de pagament no vàlida %1</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation>L'URI no pot ser analitzat! Això pot ser a causa d'una adreça de Bitcoin no vàlida o per paràmetres URI amb mal format.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Gestió de fitxers de les sol·licituds de pagament</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>No es pot llegir el fitxer de la sol·licitud de pagament. Això pot ser causat per un fitxer de sol·licitud de pagament no vàlid.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>La sol·licitud de pagament s'ha rebutjat</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>La xarxa de la sol·licitud de pagament no coincideix amb la xarxa del client.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>La sol·licitud de pagament ha vençut.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>La sol·licitud de pagament no està inicialitzada.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>No s'accepten sol·licituds de pagament no verificades a scripts de pagament personalitzats.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Sol·licitud de pagament no vàlida.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>L'import de pagament sol·licitat %1 és massa petit (es considera polsim).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Reemborsament de %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>La sol·licitud de pagament %1 és massa gran (%2 bytes, permés %3 bytes).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Error en comunicar amb %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>No es pot analitzar la sol·licitud de pagament!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Mala resposta del servidor %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Error en la sol·licitud de xarxa</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Pagament reconegut</translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -823,11 +1164,7 @@
<source>Node/Service</source>
<translation>Node/Servei</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Temps de ping</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -866,6 +1203,32 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 i %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Guarda la imatge...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Copia la imatge</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Guarda el codi QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Imatge PNG (*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1106,7 +1469,7 @@
</message>
<message>
<source>Clear all fields of the form.</source>
- <translation>Esborra tots els camps del formuari.</translation>
+ <translation>Netejar tots els camps del formulari.</translation>
</message>
<message>
<source>Clear</source>
@@ -1136,6 +1499,18 @@
<source>Remove</source>
<translation>Esborra</translation>
</message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Copia el missatge</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1155,8 +1530,67 @@
<source>&amp;Save Image...</source>
<translation>&amp;Guarda la imatge...</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Sol·licita un pagament a %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informació de pagament</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreça</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Import</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Missatge</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>URI resultant massa llarga, intenta reduir el text per a la etiqueta / missatge</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Error en codificar l'URI en un codi 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>Missatge</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(sense missatge)</translation>
+ </message>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -1191,12 +1625,8 @@
<translation>Import:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritat:</translation>
- </message>
- <message>
<source>Fee:</source>
- <translation>Comissió:</translation>
+ <translation>Comissió</translation>
</message>
<message>
<source>After Fee:</source>
@@ -1263,10 +1693,6 @@
<translation>(No s'ha inicialitzat encara la comissió intel·ligent. Normalment pren uns pocs blocs...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Temps de confirmació:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1306,6 +1732,98 @@
<source>S&amp;end</source>
<translation>E&amp;nvia</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copia la quantitat</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copia la comissió</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copia la comissió posterior</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copia els bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copia el polsim</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copia el canvi</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>Esteu segur que ho voleu enviar?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>S'ha afegit una taxa de transacció</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>o</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Confirma l'enviament de monedes</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>L'adreça de destinatari no és vàlida. Torneu-la a comprovar.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>L'import a pagar ha de ser major que 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>L'import supera el vostre balanç.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>El total excedeix el teu balanç quan s'afig la comissió a la transacció %1.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>S'ha trobat una adreça duplicada: cal utilitzar les adreces només un cop cada vegada.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Ha fallat la creació de la transacció!</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Una comissió superior a %1 es considera una comissió absurdament alta.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>La sol·licitud de pagament ha vençut.</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Avís: adreça Bitcoin no vàlida</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Avís: adreça de canvi desconeguda</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1323,7 +1841,7 @@
</message>
<message>
<source>Choose previously used address</source>
- <translation>Trieu una adreça feta servir anteriorment</translation>
+ <translation>Tria les adreces fetes servir amb anterioritat</translation>
</message>
<message>
<source>This is a normal payment.</source>
@@ -1335,11 +1853,11 @@
</message>
<message>
<source>Alt+A</source>
- <translation>Alta+A</translation>
+ <translation>Alt+A</translation>
</message>
<message>
<source>Paste address from clipboard</source>
- <translation>Apegar adreça del porta-retalls</translation>
+ <translation>Apega l'adreça del porta-retalls</translation>
</message>
<message>
<source>Alt+P</source>
@@ -1385,6 +1903,17 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Introduïu una etiqueta per a esta adreça per afegir-la a la llibreta d'adreces</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Sí</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1479,6 +2008,58 @@
<source>Reset all verify message fields</source>
<translation>Neteja tots els camps de verificació de missatge</translation>
</message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Feu clic a «Signa el missatge» per a generar una signatura</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>L'adreça introduïda no és vàlida.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Comproveu l'adreça i torneu-ho a provar.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>L'adreça introduïda no referencia a cap clau.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>El desbloqueig del moneder ha estat cancelat.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>La clau privada per a la adreça introduïda no està disponible.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>La signatura del missatge ha fallat.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Missatge signat.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>La signatura no s'ha pogut descodificar.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Comproveu la signatura i torneu-ho a provar.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>La signatura no coincideix amb el resum del missatge.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Ha fallat la verificació del missatge.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Missatge verificat.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1495,11 +2076,396 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Open until %1</source>
+ <translation>Obert fins %1</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/fora de línia</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/sense confirmar</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 confirmacions</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Estat</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, encara no ha estat emés correctement</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Font</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Generat</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Des de</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconegut</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>Adreça pròpia</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>només lectura</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etiqueta</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Crèdit</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>no acceptat</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>Transaction fee</source>
+ <translation>Comissió de transacció</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Import net</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Missatge</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Comentar</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>ID de transacció</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Mercader</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>Les monedes generades han de madurar %1 blocs abans de poder ser gastades. Quan genereu este bloc, es farà saber a la xarxa per tal d'afegir-lo a la cadena de blocs. Si no pot fer-se lloc a la cadena, el seu estat canviarà a «no acceptat» i no es podrà gastar. Això pot passar ocasionalment si un altre node genera un bloc en un marge de segons respecte al vostre.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Informació de depuració</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transacció</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Entrades</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Import</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>cert</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>fals</translation>
+ </message>
+</context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Este panell mostra una descripció detallada de la transacció</translation>
</message>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipus</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Obert fins %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Fora de línia</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Sense confirmar</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Confirmant (%1 de %2 confirmacions recomanades)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Confirmat (%1 confirmacions)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>En conflicte</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Immadur (%1 confirmacions, serà disponible després de %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Este bloc no ha estat rebut per cap altre node i probablement no serà acceptat!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Generat però no acceptat</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Rebut amb</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Rebut de</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviat a</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Pagament a un mateix</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minat</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>només lectura</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/a)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Estat de la transacció. Desplaceu-vos sobre este camp per mostrar el nombre de confirmacions.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Data i hora en que la transacció va ser rebuda.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Tipus de transacció.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Si està implicada o no una adreça només de lectura en la transacció.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Intenció/propòsit de la transacció definida per l'usuari.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Import extret o afegit del balanç.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Tot</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Hui</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Esta setmana</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Este mes</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>El mes passat</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Enguany</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Rang...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Rebut amb</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviat a</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>A un mateix</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minat</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Altres</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Introduïu una adreça o una etiqueta per cercar</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Import mínim</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Copiar adreça </translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copiar ID de transacció</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Editar etiqueta</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Mostra detalls de la transacció</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exporta l'historial de transacció</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Fitxer de separació amb comes (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Confirmat</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Només de lectura</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipus</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreça</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>L'exportació ha fallat</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>S'ha produït un error en provar de guardar l'historial de transacció a %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Exportació amb èxit</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>L'historial de transaccions s'ha guardat correctament a %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Rang:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>a</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1509,6 +2475,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>No s'ha carregat cap moneder.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Envia monedes</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Exporta</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Exporta les dades de la pestanya actual a un fitxer</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Còpia de seguretat del moneder</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Dades del moneder (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Ha fallat la còpia de seguretat</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>S'ha produït un error en provar de guardar les dades del moneder a %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>La còpia de seguretat s'ha realitzat correctament</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>S'han guardat les dades del moneder correctament a %1.</translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1531,12 +2546,16 @@
<translation>Accepta la línia d'ordes i ordes JSON-RPC </translation>
</message>
<message>
- <source>Run in the background as a daemon and accept commands</source>
- <translation>Executa en segon pla com a programa dimoni i accepta ordes</translation>
+ <source>Error: A fatal internal error occurred, see debug.log for details</source>
+ <translation>Error: s'ha produït un error intern fatal. Vegeu debug.log per a més detalls</translation>
+ </message>
+ <message>
+ <source>Pruning blockstore...</source>
+ <translation>S'està podant l'emmagatzemament de blocs...</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Accepta connexions de fora (per defecte: 1 si no -proxy o -connect)</translation>
+ <source>Run in the background as a daemon and accept commands</source>
+ <translation>Executa en segon pla com a programa dimoni i accepta ordes</translation>
</message>
<message>
<source>Bitcoin Core</source>
@@ -1551,10 +2570,6 @@
<translation>Elimina totes les transaccions del moneder i només recupera aquelles de la cadena de blocs a través de -rescan a l'inici</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuït sota llicència de programari MIT. Vegeu el fitxer acompanyant COPYING o &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Executa una orde quan una transacció del moneder canvie (%s en cmd es canvia per TxID)</translation>
</message>
@@ -1563,22 +2578,6 @@
<translation>Defineix el nombre de fils de verificació d'scripts (%u a %d, 0 = auto, &lt;0 = deixa tants nuclis lliures, per defecte: %d)</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 és una versió de pre-llançament - utilitza-la sota la teva responsabilitat - No usar per a minería o aplicacions de compra-venda</translation>
- </message>
- <message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Avís: la xarxa no pareix que hi estiga plenament d'acord. Alguns miners pareix que estan experimentant problemes.</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>Avís: pareix que no estem plenament d'acord amb els nostres iguals! Podria caldre que actualitzar l'aplicació, o potser que ho facen altres nodes.</translation>
- </message>
- <message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Afig a la llista blanca els iguals que es connecten de la màscara de xarxa o adreça IP donada. Es pot especificar moltes vegades.</translation>
- </message>
- <message>
<source>&lt;category&gt; can be:</source>
<translation>&lt;category&gt; pot ser:</translation>
</message>
@@ -1587,10 +2586,6 @@
<translation>Opcions de la creació de blocs:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Connecta només al(s) node(s) especificats</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Opcions de connexió:</translation>
</message>
@@ -1735,10 +2730,6 @@
<translation>Mida màxima de les dades en les transaccions de l'operador en què confiem i en les meues (per defecte: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Consulta a adreces d'iguals a través de DNS, si es troba baix en adreces (per defecte: 1 a menys que -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Genera a l'atzar credencials per a cada connexió proxy. Això habilita l'aïllament del flux de Tor (per defecte: %u)</translation>
</message>
@@ -1751,10 +2742,6 @@
<translation>L'import de la transacció és massa petit per enviar-la després que se'n deduïsca la comissió</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Este producte inclou programari desenvolupat pel projecte OpenSSL per a ús a l'OpenSSL Toolkit &lt;https://www.openssl.org/&gt; i programari criptogràfic escrit per Eric Young i programari UPnP escrit per Thomas Bernard.</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>Els iguals en la llista blanca no poden ser bandejats per DoS i es transmetran sempre llurs transaccions, fins i tot si ja són a la mempool. Això és útil, p. ex., per a una passarel·la</translation>
</message>
@@ -1780,7 +2767,7 @@
</message>
<message>
<source>Information</source>
- <translation>&amp;Informació</translation>
+ <translation>Informació</translation>
</message>
<message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
@@ -1839,10 +2826,6 @@
<translation>Import de la transacció massa petit</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Els imports de les transaccions han de ser positius</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transacció massa gran per a la política de comissions</translation>
</message>
@@ -1967,10 +2950,6 @@
<translation>Defineix la mida clau disponible a &lt;n&gt; (per defecte: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Defineix la mida de bloc mínima en bytes (per defecte: %u)</translation>
- </message>
- <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>Defineix el nombre de fils a crides de servei RPC (per defecte: %d)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts
index f985a6928d..8cbb57bd35 100644
--- a/src/qt/locale/bitcoin_ca_ES.ts
+++ b/src/qt/locale/bitcoin_ca_ES.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Elimina</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Trieu l'adreça on enviar les monedes</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Trieu l'adreça on rebre les monedes</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Tria</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Adreces d'enviament</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Adreces de recepció</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>Aquestes són les vostres adreces de Bitcoin per enviar els pagaments. Sempre reviseu l'import i l'adreça del destinatari abans de transferir monedes.</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>Aquestes són les vostres adreces Bitcoin per rebre pagaments. Es recomana utilitzar una adreça nova de recepció per a cada transacció.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Copia l'adreça</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copia l'eti&amp;queta</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Edita</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exporta la llista d'adreces</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Fitxer separat per comes (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>L'exportació ha fallat</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>S'ha produït un error en desar la llista d'adreces a %1. Torneu-ho a provar.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreça</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>Repetiu la nova contrasenya</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>Introduïu la contrasenya nova al moneder.&lt;br/&gt;Utilitzeu una contrasenya de &lt;b&gt;deu o més caràcters aleatoris&lt;/b&gt;, o &lt;b&gt;vuit o més paraules&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Encripta el moneder</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Aquesta operació requereix la contrasenya del moneder per a desbloquejar-lo.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Desbloqueja el moneder</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Aquesta operació requereix la contrasenya del moneder per desencriptar-lo.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Desencripta el moneder</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Canvia la contrasenya</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Introduïu la contrasenya antiga i la contrasenya nova al moneder.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Confirma l'encriptació del moneder</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>Avís: si encripteu el vostre moneder i perdeu la contrasenya, &lt;b&gt;PERDREU TOTS ELS VOSTRES BITCOINS&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Esteu segur que voleu encriptar el vostre moneder?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Moneder encriptat</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>Ara es tancarà el %1 per finalitzar el procés d'encriptació. Recordeu que encriptar el vostre moneder no garanteix que les vostres bitcoins no puguin ser robades per programari maliciós que infecti l'ordinador.</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>IMPORTANT: Tota copia de seguretat que hàgiu realitzat hauria de ser reemplaçada pel, recentment generat, fitxer encriptat del moneder. Per motius de seguretat, les còpies de seguretat anteriors del fitxer de moneder no encriptat esdevindran inusables tan aviat com començar a utilitzar el nou moneder encriptat.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>L'encriptació del moneder ha fallat</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>L'encriptació del moneder ha fallat per un error intern. El moneder no ha estat encriptat.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Les contrasenyes introduïdes no coincideixen.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>El desbloqueig del moneder ha fallat</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>La contrasenya introduïda per a desencriptar el moneder és incorrecta.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>La desencriptació del moneder ha fallat</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>La contrasenya del moneder ha estat modificada correctament.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Avís: Les lletres majúscules estan activades!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -111,6 +270,14 @@
<translation>Surt de l'aplicació</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>Qu&amp;ant al %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Mosta informació sobre el %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>Quant a &amp;Qt</translation>
</message>
@@ -123,6 +290,10 @@
<translation>&amp;Opcions...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Modifica les opcions de configuració de %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Encripta el moneder...</translation>
</message>
@@ -140,13 +311,25 @@
</message>
<message>
<source>&amp;Receiving addresses...</source>
- <translation>Adreces de &amp;recepció</translation>
+ <translation>Adreces de &amp;recepció...</translation>
</message>
<message>
<source>Open &amp;URI...</source>
<translation>Obre un &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Feu clic per inhabilitar l'activitat de la xarxa.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>S'ha inhabilitat l'activitat de la xarxa.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Feu clic per tornar a habilitar l'activitat de la xarxa.</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>S'estan reindexant els blocs al disc...</translation>
</message>
@@ -251,32 +434,16 @@
<translation><numerusform>%n connexió activa a la xarxa Bitcoin</numerusform><numerusform>%n connexions actives a la xarxa Bitcoin</numerusform></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'han processat %n bloc de l'historial de transacció.</numerusform><numerusform>S'han processat %n blocs de l'historial de transacció.</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n hora</numerusform><numerusform>%n hores</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n dia</numerusform><numerusform>%n dies</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n setmana</numerusform><numerusform>%n setmanes</numerusform></translation>
+ <source>Indexing blocks on disk...</source>
+ <translation>S'estan indexant els blocs al disc...</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 i %2</translation>
+ <source>Processing blocks on disk...</source>
+ <translation>S'estan processant els blocs al disc...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n any</numerusform><numerusform>%n anys</numerusform></translation>
+ <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>
</message>
<message>
<source>%1 behind</source>
@@ -300,13 +467,21 @@
</message>
<message>
<source>Information</source>
- <translation>Informació</translation>
+ <translation>&amp;Informació</translation>
</message>
<message>
<source>Up to date</source>
<translation>Al dia</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Mostra el missatge d'ajuda del %1 per obtenir una llista amb les possibles opcions de línia d'ordres de Bitcoin</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>Client de %1</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>S'està posant al dia ...</translation>
</message>
@@ -349,6 +524,14 @@
<translation>Transacció entrant</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>La generació de la clau HD és &lt;b&gt;habilitada&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>La generació de la clau HD és &lt;b&gt;inhabilitada&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>El moneder està &lt;b&gt;encriptat&lt;/b&gt; i actualment &lt;b&gt;desbloquejat&lt;/b&gt;</translation>
</message>
@@ -356,6 +539,10 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>El moneder està &lt;b&gt;encriptat&lt;/b&gt; i actualment &lt;b&gt;bloquejat&lt;/b&gt;</translation>
</message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>S'ha produït un error fatal. Bitcoin no pot continuar amb seguretat i finalitzarà.</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -376,12 +563,8 @@
<translation>Import:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritat:</translation>
- </message>
- <message>
<source>Fee:</source>
- <translation>Comissió</translation>
+ <translation>Comissió:</translation>
</message>
<message>
<source>Dust:</source>
@@ -432,8 +615,84 @@
<translation>Confirmat</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Prioritat</translation>
+ <source>Copy address</source>
+ <translation>Copia l'adreça</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copia l'etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copia l'ID de transacció</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Bloqueja sense gastar</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Desbloqueja sense gastar</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copia la quantitat</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copia la comissió</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copia la comissió posterior</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copia els bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copia el polsim</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copia el canvi</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 bloquejada)</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>Aquesta etiqueta es torna vermella si cap recipient rep un import inferior al llindar de polsim actual.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Pot variar en +/- %1 satoshi(s) per entrada.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>canvia de %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(canvia)</translation>
</message>
</context>
<context>
@@ -458,6 +717,38 @@
<source>&amp;Address</source>
<translation>&amp;Adreça</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nova adreça de recepció</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nova adreça d'enviament</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Edita l'adreça de recepció</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Edita l'adreça d'enviament</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>L'adreça introduïda «%1» no és una adreça de Bitcoin vàlida.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>L'adreça introduïda «%1» ja és present a la llibreta d'adreces.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>No s'ha pogut desbloquejar el moneder.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Ha fallat la generació d'una clau nova.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -493,6 +784,10 @@
<translation>(%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>Quant al %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Opcions de línia d'ordres</translation>
</message>
@@ -528,12 +823,28 @@
<source>Show splash screen on startup (default: %u)</source>
<translation>Mostra la pantalla de benvinguda a l'inici (per defecte: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Reinicialitza tots els canvis de configuració fets des de la interfície gràfica</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
<source>Welcome</source>
- <translation>Us donem la benviguda</translation>
+ <translation>Us donem la benvinguda</translation>
+ </message>
+ <message>
+ <source>Welcome to %1.</source>
+ <translation>Us donem la benvinguda a %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>Com és la primera vegada que s'executa el programa, podeu triar on %1 emmagatzemarà les dades.</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>%1 baixarà i emmagatzemarà una còpia de la cadena de blocs de Bitcoin. Com a mínim %2GB de dades s'emmagatzemaran en aquest directori, i augmentarà al llarg del temps. El moneder també s'emmagatzemarà en aquest directori.</translation>
</message>
<message>
<source>Use the default data directory</source>
@@ -561,6 +872,37 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulari</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Últim temps de bloc</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>Progrés</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>s'està calculant...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Temps estimat restant fins sincronitzat</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Amaga</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Desconegut. Sincronització de les capçaleres (%1)...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -578,6 +920,10 @@
<source>Select payment request file</source>
<translation>Selecciona un fitxer de sol·licitud de pagament</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Seleccioneu el fitxer de sol·licitud de pagament per obrir</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -590,6 +936,14 @@
<translation>&amp;Principal</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>Inicieu %1 automàticament després d'entrar en el sistema.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>&amp;Inicia %1 en l'entrada al sistema</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>Mida de la memòria cau de la base de &amp;dades</translation>
</message>
@@ -726,6 +1080,14 @@
<translation>&amp;Finestra</translation>
</message>
<message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>Ama&amp;ga la icona de la safata del sistema.</translation>
+ </message>
+ <message>
+ <source>Hide tray icon</source>
+ <translation>Amaga la icona de la safata</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation>Mostra només la icona de la barra en minimitzar la finestra.</translation>
</message>
@@ -746,6 +1108,10 @@
<translation>&amp;Llengua de la interfície d'usuari:</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>Aquí es pot definir la llengua de la interfície d'usuari. Aquest paràmetre tindrà efecte en reiniciar el %1.</translation>
+ </message>
+ <message>
<source>&amp;Unit to show amounts in:</source>
<translation>&amp;Unitats per mostrar els imports en:</translation>
</message>
@@ -870,6 +1236,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Error de la sol·licitud de pagament</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>No es pot iniciar bitcoin: controlador click-to-pay</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Gestió d'URI</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>L'URL de recuperació de la sol·licitud de pagament no és vàlida: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Adreça de pagament no vàlida %1</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation>L'URI no pot ser analitzat! Això pot ser a causa d'una adreça de Bitcoin no vàlida o per paràmetres URI amb mal format.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Gestió de fitxers de les sol·licituds de pagament</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>No es pot llegir el fitxer de la sol·licitud de pagament. Això pot ser causat per un fitxer de sol·licitud de pagament no vàlid.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>La sol·licitud de pagament s'ha rebutjat</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>La xarxa de la sol·licitud de pagament no coincideix amb la xarxa del client.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>La sol·licitud de pagament ha vençut.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>La sol·licitud de pagament no està inicialitzada.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>No s'accepten sol·licituds de pagament no verificades a scripts de pagament personalitzats.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Sol·licitud de pagament no vàlida.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>L'import de pagament sol·licitat %1 és massa petit (es considera polsim).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Reemborsament de %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>La sol·licitud de pagament %1 és massa gran (%2 bytes, permès %3 bytes).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Error en comunicar amb %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>No es pot analitzar la sol·licitud de pagament!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Mala resposta del servidor %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Error en la sol·licitud de xarxa</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Pagament reconegut</translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -879,11 +1336,7 @@
<source>Node/Service</source>
<translation>Node/Servei</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Temps de ping</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -922,6 +1375,32 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 i %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>De&amp;sa la imatge...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Copia la imatge</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Desa el codi QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Imatge PNG (*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -950,6 +1429,10 @@
<translation>Utilitzant BerkeleyDB versió</translation>
</message>
<message>
+ <source>Datadir</source>
+ <translation>Datadir</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>&amp;Temps d'inici</translation>
</message>
@@ -1110,14 +1593,6 @@
<translation>Neteja la consola</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Desconnecta el node</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Bandeja el node durant</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;hora</translation>
</message>
@@ -1134,10 +1609,6 @@
<translation>1 &amp;any</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Desbandeja el node</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>Utilitza les fletxes d'amunt i avall per navegar per l'historial, i &lt;b&gt;Ctrl-L&lt;\b&gt; per netejar la pantalla.</translation>
</message>
@@ -1264,6 +1735,18 @@
<source>Remove</source>
<translation>Esborra</translation>
</message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copia l'etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Copia el missatge</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1283,6 +1766,73 @@
<source>&amp;Save Image...</source>
<translation>De&amp;sa la imatge...</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Sol·licita un pagament a %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informació de pagament</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreça</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Import</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Missatge</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>URI resultant massa llarga, intenta reduir el text per a la etiqueta / missatge</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Error en codificar l'URI en un codi 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>Missatge</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(sense missatge)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(no s'ha sol·licitat import)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Sol·licitat</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1319,10 +1869,6 @@
<translation>Import:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritat:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Comissió:</translation>
</message>
@@ -1391,10 +1937,6 @@
<translation>(No s'ha inicialitzat encara la comissió intel·ligent. Normalment pren uns pocs blocs...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Temps de confirmació:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1412,7 +1954,7 @@
</message>
<message>
<source>Clear all fields of the form.</source>
- <translation>Netejar tots els camps del formulari.</translation>
+ <translation>Esborra tots els camps del formuari.</translation>
</message>
<message>
<source>Dust:</source>
@@ -1434,6 +1976,106 @@
<source>S&amp;end</source>
<translation>E&amp;nvia</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copia la quantitat</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copia la comissió</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copia la comissió posterior</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copia els bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copia el polsim</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copia el canvi</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>Esteu segur que ho voleu enviar?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>S'ha afegit una taxa de transacció</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Import total %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>o</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Confirma l'enviament de monedes</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>L'adreça del destinatari no és vàlida. Torneu-la a comprovar.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>L'import a pagar ha de ser major que 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>L'import supera el vostre balanç.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>El total excedeix el vostre balanç quan s'afegeix la comissió a la transacció %1.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>S'ha trobat una adreça duplicada: les adreces només s'haurien d'utilitzar una vegada cada una.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>La creació de la transacció ha fallat!</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Una comissió superior a %1 es considera una comissió absurdament alta.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>La sol·licitud de pagament ha vençut.</translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Paga només la comissió necessària de %1</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Avís: adreça Bitcoin no vàlida</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Avís: adreça de canvi desconeguda</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1513,6 +2155,17 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Introduïu una etiqueta per a aquesta adreça per afegir-la a la llibreta d'adreces</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Sí</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1541,15 +2194,15 @@
</message>
<message>
<source>Choose previously used address</source>
- <translation>Tria les adreces fetes servir amb anterioritat</translation>
+ <translation>Escull una adreça feta servir anteriorment</translation>
</message>
<message>
<source>Alt+A</source>
- <translation>Alt+A</translation>
+ <translation>Alta+A</translation>
</message>
<message>
<source>Paste address from clipboard</source>
- <translation>Enganxa l'adreça del porta-retalls</translation>
+ <translation>Enganxar adreça del porta-retalls</translation>
</message>
<message>
<source>Alt+P</source>
@@ -1607,6 +2260,58 @@
<source>Reset all verify message fields</source>
<translation>Neteja tots els camps de verificació de missatge</translation>
</message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Feu clic a «Signa el missatge» per a generar una signatura</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>L'adreça introduïda no és vàlida.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Comproveu l'adreça i torneu-ho a provar.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>L'adreça introduïda no referencia a cap clau.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>El desbloqueig del moneder ha estat cancelat.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>La clau privada per a la adreça introduïda no està disponible.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>La signatura del missatge ha fallat.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Missatge signat.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>La signatura no s'ha pogut descodificar.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Comproveu la signatura i torneu-ho a provar.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>La signatura no coincideix amb el resum del missatge.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Ha fallat la verificació del missatge.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Missatge verificat.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1623,11 +2328,404 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Open until %1</source>
+ <translation>Obert fins %1</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/fora de línia</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/sense confirmar</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 confirmacions</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Estat</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, encara no ha estat emès correctement</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Font</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Generada</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>De</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconegut</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>adreça pròpia</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>només lectura</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etiqueta</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Crèdit</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>no acceptat</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>Transaction fee</source>
+ <translation>Comissió de transacció</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Import net</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Missatge</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Comentari</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>ID de la transacció</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Mercader</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>Les monedes generades han de madurar %1 blocs abans de poder ser gastades. Quan genereu aquest bloc, es farà saber a la xarxa per tal d'afegir-lo a la cadena de blocs. Si no pot fer-se lloc a la cadena, el seu estat canviarà a «no acceptat» i no es podrà gastar. Això pot passar ocasionalment si un altre node genera un bloc en un marge de segons respecte al vostre.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Informació de depuració</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transacció</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Entrades</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Import</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>cert</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>fals</translation>
+ </message>
+</context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Aquest panell mostra una descripció detallada de la transacció</translation>
</message>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipus</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Obert fins %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Fora de línia</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Sense confirmar</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Abandonada</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Confirmant (%1 de %2 confirmacions recomanades)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Confirmat (%1 confirmacions)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>En conflicte</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Immadur (%1 confirmacions, serà disponible després de %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Aquest bloc no ha estat rebut per cap altre node i probablement no serà acceptat!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Generat però no acceptat</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Rebuda amb</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Rebuda de</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviada a</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Pagament a un mateix</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minada</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>només lectura</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/a)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sense etiqueta)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Estat de la transacció. Desplaceu-vos sobre aquest camp per mostrar el nombre de confirmacions.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Data i hora en que la transacció va ser rebuda.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Tipus de transacció.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Si està implicada o no una adreça només de lectura en la transacció.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Intenció/propòsit de la transacció definida per l'usuari.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Import extret o afegit del balanç.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Tot</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Avui</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Aquesta setmana</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Aquest mes</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>El mes passat</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Enguany</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Rang...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Rebuda amb</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviada a</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>A un mateix</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minada</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Altres</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Introduïu una adreça o una etiqueta per cercar</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Import mínim</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Copia l'adreça</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copia l'etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'import</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copia l'ID de transacció</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Copia la transacció crua</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Editar etiqueta</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Mostra detalls de la transacció</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exporta l'historial de transacció</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Fitxer separat per comes (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Confirmat</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Només de lectura</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipus</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreça</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>L'exportació ha fallat</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>S'ha produït un error en provar de desar l'historial de transacció a %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Exportació amb èxit</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>L'historial de transaccions s'ha desat correctament a %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Rang:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>a</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1637,6 +2735,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>No s'ha carregat cap moneder.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Envia monedes</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Exporta</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Exporta les dades de la pestanya actual a un fitxer</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Còpia de seguretat del moneder</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Dades del moneder (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Ha fallat la còpia de seguretat</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>S'ha produït un error en provar de desar les dades del moneder a %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>La còpia de seguretat s'ha realitzat correctament</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>S'han desat les dades del moneder correctament a %1.</translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1671,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>
@@ -1699,12 +2842,8 @@
<translation>No s'ha pogut iniciar el servidor HTTP. Vegeu debug.log per a més detalls.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Accepta connexions de fora (per defecte: 1 si no -proxy o -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
- <translation>Nucli de Bitcoin</translation>
+ <translation>Bitcoin Core</translation>
</message>
<message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
@@ -1715,10 +2854,6 @@
<translation>Elimina totes les transaccions del moneder i només recupera aquelles de la cadena de blocs a través de -rescan a l'inici</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuït sota llicència de programari MIT. Vegeu el fitxer acompanyant COPYING o &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Executa una ordre quan una transacció del moneder canviï (%s en cmd es canvia per TxID)</translation>
</message>
@@ -1727,22 +2862,6 @@
<translation>Defineix el nombre de fils de verificació d'scripts (%u a %d, 0 = auto, &lt;0 = deixa tants nuclis lliures, per defecte: %d)</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>Aquesta és una versió de pre-llançament - utilitza-la sota la teva responsabilitat - No usar per a minería o aplicacions de compra-venda</translation>
- </message>
- <message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Avís: la xarxa no sembla que hi estigui plenament d'acord. Alguns miners sembla que estan experimentant problemes.</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>Avís: sembla que no estem plenament d'acord amb els nostres iguals! Podria caler que actualitzar l'aplicació, o potser que ho facin altres nodes.</translation>
- </message>
- <message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Afegeix a la llista blanca els iguals que es connecten de la màscara de xarxa o adreça IP donada. Es pot especificar moltes vegades.</translation>
- </message>
- <message>
<source>&lt;category&gt; can be:</source>
<translation>&lt;category&gt; pot ser:</translation>
</message>
@@ -1751,10 +2870,6 @@
<translation>Opcions de la creació de blocs:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Connecta només al(s) node(s) especificats</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Opcions de connexió:</translation>
</message>
@@ -1843,6 +2958,10 @@
<translation>Utilitza UPnP per a mapejar el port d'escolta (per defecte: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Utilitza la cadena de proves</translation>
+ </message>
+ <message>
<source>Verifying blocks...</source>
<translation>S'estan verificant els blocs...</translation>
</message>
@@ -1855,6 +2974,14 @@
<translation>El moneder %s resideix fora del directori de dades %s</translation>
</message>
<message>
+ <source>Wallet debugging/testing options:</source>
+ <translation>Opcions de depuració/proves del moneder:</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>Cal reescriure el moneder: reinicieu %s per a completar-ho</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Opcions de moneder:</translation>
</message>
@@ -1899,10 +3026,6 @@
<translation>Mida màxima de les dades en les transaccions de l'operador en què confiem i en les meves (per defecte: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Consulta a adreces d'iguals a través de DNS, si es troba baix en adreces (per defecte: 1 a menys que -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Genera a l'atzar credencials per a cada connexió proxy. Això habilita l'aïllament del flux de Tor (per defecte: %u)</translation>
</message>
@@ -1915,10 +3038,6 @@
<translation>L'import de la transacció és massa petit per enviar-la després que se'n dedueixi la comissió</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Aquest producte inclou programari desenvolupat pel projecte OpenSSL per a ús a l'OpenSSL Toolkit &lt;https://www.openssl.org/&gt; i programari criptogràfic escrit per Eric Young i programari UPnP escrit per Thomas Bernard.</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>Els iguals en la llista blanca no poden ser bandejats per DoS i es transmetran sempre llurs transaccions, fins i tot si ja són a la mempool. Això és útil, p. ex., per a una passarel·la</translation>
</message>
@@ -2003,10 +3122,6 @@
<translation>Import de la transacció massa petit</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Els imports de les transaccions han de ser positius</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transacció massa gran per a la política de comissions</translation>
</message>
@@ -2131,10 +3246,6 @@
<translation>Defineix la mida clau disponible a &lt;n&gt; (per defecte: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Defineix la mida de bloc mínima en bytes (per defecte: %u)</translation>
- </message>
- <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>Defineix el nombre de fils a crides de servei RPC (per defecte: %d)</translation>
</message>
@@ -2155,10 +3266,22 @@
<translation>Gasta el canvi no confirmat en enviar les transaccions (per defecte: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>S'estan iniciant els fils de la xarxa...</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Llindar per a desconnectar els iguals de comportament qüestionable (per defecte: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Els imports de la transacció no han de ser negatius</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>La transacció ha de tenir com a mínim un destinatari</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Xarxa desconeguda especificada a -onlynet: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts
index 2dfa295ce0..f38c425137 100644
--- a/src/qt/locale/bitcoin_cs.ts
+++ b/src/qt/locale/bitcoin_cs.ts
@@ -15,7 +15,7 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation>Zkopíruj aktuálně vybranou adresu do systémové schránky</translation>
+ <translation>Zkopíruj tuto adresu do systémové schránky</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -27,7 +27,7 @@
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation>Smaž zvolenou adresu ze seznamu</translation>
+ <translation>Smaž tuto adresu ze seznamu</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>S&amp;maž</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Zvol adresu, na kterou pošleš mince</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Zvol adres na příjem mincí</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Zvol</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Odesílací adresy</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Přijímací 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>Tohle jsou tvé bitcoinové adresy pro posílání plateb. Před odesláním mincí si vždy zkontroluj částku a cílovou adresu.</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>Tohle jsou tvé bitcoinové adresy pro příjem plateb. Nezapomeň si pro každou transakci vždy vygenerovat novou adresu.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopíruj adresu</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopíruj &amp;označení</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Uprav</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Export seznamu adres</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Formát CSV (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Exportování selhalo</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Při ukládání seznamu adres do %1 se přihodila nějaká chyba. Zkus to prosím znovu.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Označení</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresa</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(bez označení)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,10 +131,106 @@
<source>Repeat new passphrase</source>
<translation>Totéž heslo ještě jednou</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>Zadej nové heslo k peněžence.&lt;br/&gt;Použij &lt;b&gt;alespoň deset náhodných znaků&lt;/b&gt; nebo &lt;b&gt;alespoň osm slov&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Zašifruj peněženku</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>K provedení této operace musíš zadat heslo k peněžence, aby se mohla odemknout.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Odemkni peněženku</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>K provedení této operace musíš zadat heslo k peněžence, aby se mohla dešifrovat.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dešifruj peněženku</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Změň heslo</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Zadej staré a nové heslo k peněžence.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Potvrď zašifrování peněž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>Upozornění: Pokud si zašifruješ peněženku a ztratíš či zapomeneš heslo, &lt;b&gt;PŘIJDEŠ O VŠECHNY BITCOINY&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Jsi si jistý, že chceš peněženku zašifrovat?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Peněženka je zašifrována</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 se teď ukončí, aby dokončil zašifrování. Pamatuj však, že pouhé zašifrování peněženky nemůže zabránit krádeži tvých bitcoinů malwarem, kterým se může počítač nakazit.</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šechny předchozí zálohy peněženky by měly být nahrazeny nově vygenerovanou, zašifrovanou peněženkou. Z bezpečnostních důvodů budou předchozí zálohy nešifrované peněženky nepoužitelné, jakmile začneš používat novou zašifrovanou peněženku.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Zašifrování peněženky selhalo</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Zašifrování peněženky selhalo kvůli vnitřní chybě. Tvá peněženka tedy nebyla zašifrována.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Zadaná hesla nejsou shodná.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Nepodařilo se odemknout peněženku</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Nezadal jsi správné heslo pro dešifrování peněženky.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Nepodařilo se dešifrovat peněženku</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Heslo k peněžence bylo v pořádku změněno.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Upozornění: Caps Lock je zapnutý!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
- </context>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Maska</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Blokován do</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
@@ -103,6 +270,14 @@
<translation>Ukonči aplikaci</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>O &amp;%1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Zobraz informace o %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>O &amp;Qt</translation>
</message>
@@ -115,6 +290,10 @@
<translation>&amp;Možnosti...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Uprav nastavení %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>Zaši&amp;fruj peněženku...</translation>
</message>
@@ -139,12 +318,28 @@
<translation>Načíst &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Kliknutím zařízneš spojení se sítí.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Síť je vypnutá.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <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>
<message>
<source>Send coins to a Bitcoin address</source>
- <translation>Pošli mince na Bitcoinovou adresu</translation>
+ <translation>Pošli mince na bitcoinovou adresu</translation>
</message>
<message>
<source>Backup wallet to another location</source>
@@ -196,11 +391,11 @@
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation>Podepiš zprávy svými Bitcoinovými adresami, čímž prokážeš, že jsi jejich vlastníkem</translation>
+ <translation>Podepiš zprávy svými bitcoinovými adresami, čímž prokážeš, že jsi jejich vlastníkem</translation>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation>Ověř zprávy, aby ses ujistil, že byly podepsány danými Bitcoinovými adresami</translation>
+ <translation>Ověř zprávy, aby ses ujistil, že byly podepsány danými bitcoinovými adresami</translation>
</message>
<message>
<source>&amp;File</source>
@@ -240,39 +435,23 @@
</message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network</source>
- <translation><numerusform>%n aktivní spojení do Bitcoinové sítě</numerusform><numerusform>%n aktivní spojení do Bitcoinové sítě</numerusform><numerusform>%n aktivních spojení do Bitcoinové sítě</numerusform></translation>
+ <translation><numerusform>%n aktivní spojení do bitcoinové sítě</numerusform><numerusform>%n aktivní spojení do bitcoinové sítě</numerusform><numerusform>%n aktivních spojení do bitcoinové sítě</numerusform></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>
- </message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n hodinu</numerusform><numerusform>%n hodiny</numerusform><numerusform>%n hodin</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n den</numerusform><numerusform>%n dny</numerusform><numerusform>%n dnů</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n týden</numerusform><numerusform>%n týdny</numerusform><numerusform>%n týdnů</numerusform></translation>
+ <source>Indexing blocks on disk...</source>
+ <translation>Vytvářím index bloků na disku...</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 a %2</translation>
+ <source>Processing blocks on disk...</source>
+ <translation>Zpracovávám bloky na disku...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n rok</numerusform><numerusform>%n roky</numerusform><numerusform>%n roků</numerusform></translation>
+ <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>
</message>
<message>
<source>%1 behind</source>
- <translation>Stahuji ještě bloky transakcí za poslední %1</translation>
+ <translation>Stahuji ještě %1 bloků transakcí</translation>
</message>
<message>
<source>Last received block was generated %1 ago.</source>
@@ -280,7 +459,7 @@
</message>
<message>
<source>Transactions after this will not yet be visible.</source>
- <translation>Novější transakce zatím nejsou vidět.</translation>
+ <translation>Následné transakce ještě nebudou vidět.</translation>
</message>
<message>
<source>Error</source>
@@ -299,6 +478,18 @@
<translation>Aktuální</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Seznam argumentů Bitcoinu pro příkazovou řádku získáš v nápovědě %1</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <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>
@@ -341,6 +532,14 @@
<translation>Příchozí transakce</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>HD generování klíčů 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>HD generování klíčů 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>Peněženka je &lt;b&gt;zašifrovaná&lt;/b&gt; a momentálně &lt;b&gt;odemčená&lt;/b&gt;</translation>
</message>
@@ -348,6 +547,10 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Peněženka je &lt;b&gt;zašifrovaná&lt;/b&gt; a momentálně &lt;b&gt;zamčená&lt;/b&gt;</translation>
</message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Stala se fatální chyba. Bitcoin nemůže bezpečně pokračovat v činnosti, a proto skončí.</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -368,10 +571,6 @@
<translation>Částka:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorita:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Poplatek:</translation>
</message>
@@ -424,8 +623,84 @@
<translation>Potvrzeno</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Priorita</translation>
+ <source>Copy address</source>
+ <translation>Kopíruj adresu</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopíruj její označení</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopíruj částku</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopíruj ID transakce</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Zamkni neutracené</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Odemkni k utracení</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopíruj počet</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopíruj poplatek</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopíruj čistou částku</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopíruj bajty</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopíruj prach</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopíruj drobné</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 zamčeno)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>ano</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>ne</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Popisek zčervená, pokud má některý příjemce obdržet částku menší, než je aktuální práh pro prach.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Může se lišit o +/– %1 satoshi na každý vstup.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(bez označení)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>drobné z %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(drobné)</translation>
</message>
</context>
<context>
@@ -450,6 +725,38 @@
<source>&amp;Address</source>
<translation>&amp;Adresa</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nová přijímací adresa</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nová odesílací adresa</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Uprav přijímací adresu</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Uprav odesílací adresu</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Zadaná adresa „%1“ není platná bitcoinová adresa.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Zadaná adresa „%1“ už v adresáři je.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Nemohu odemknout peněženku.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Nepodařilo se mi vygenerovat nový klíč.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -485,6 +792,10 @@
<translation>(%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>O %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Argumenty příkazové řádky</translation>
</message>
@@ -520,7 +831,11 @@
<source>Show splash screen on startup (default: %u)</source>
<translation>Zobrazit startovací obrazovku (výchozí: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Vrátit všechny volby měněné v GUI na výchozí hodnoty</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -528,6 +843,18 @@
<translation>Vítej</translation>
</message>
<message>
+ <source>Welcome to %1.</source>
+ <translation>Vítej v %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>Tohle je poprvé, co spouštíš %1, takže si můžeš zvolit, kam bude ukládat svá data.</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>%1 bude stahovat kopii řetězce bloků. Proto bude potřeba do tohoto adresáře uložit nejméně %2 GB dat – toto číslo bude navíc v průběhu času růst. Tvá peněženka bude rovněž uložena v tomto adresáři.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Použij výchozí adresář pro data</translation>
</message>
@@ -553,6 +880,57 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulář</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ávné transakce ještě nemusí být vidět, takže stav tvého účtu nemusí být platný. Jakmile se však tvá peněženka dosynchronizuje s bitcoinovou sítí (viz informace níže), tak už bude stav správně.</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>Utrácení bitcoinů, které už utratily zatím nezobrazené transakce, nebude bitcoinovou sítí umožněno.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Zbývající počet bloků</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>neznámý…</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Čas posledního bloku</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>Stav</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Postup za hodinu</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>propočítávám…</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Odhadovaný zbývající čas</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Skryj</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Neznámý. Synchronizuji záhlaví bloků (%1)…</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -570,6 +948,10 @@
<source>Select payment request file</source>
<translation>Vyber soubor platebního požadavku</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Vyber soubor platebního požadavku k načtení</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -582,6 +964,14 @@
<translation>&amp;Hlavní</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>Automaticky spustí %1 po přihlášení do systému.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>S&amp;pustit %1 po přihlášení do systému</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>Velikost &amp;databázové cache</translation>
</message>
@@ -619,7 +1009,7 @@
</message>
<message>
<source>Active command-line options that override above options:</source>
- <translation>Aktivní argumenty z příkazové řádky, které mají přednost před nastavením výše:</translation>
+ <translation>Aktivní argumenty z příkazové řádky, které přetloukly tato nastavení:</translation>
</message>
<message>
<source>Reset all client options to default.</source>
@@ -667,7 +1057,7 @@
</message>
<message>
<source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
- <translation>Připojí se do Bitcoinové sítě přes SOCKS5 proxy.</translation>
+ <translation>Připojí se do bitcoinové sítě přes SOCKS5 proxy.</translation>
</message>
<message>
<source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
@@ -687,7 +1077,7 @@
</message>
<message>
<source>Used for reaching peers via:</source>
- <translation>Použije se k připojování k protějškům přes:</translation>
+ <translation>Použije se k připojování k protějskům přes:</translation>
</message>
<message>
<source>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
@@ -707,7 +1097,7 @@
</message>
<message>
<source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source>
- <translation>Připojí se do Bitcoinové sítě přes SOCKS5 proxy vyhrazenou pro skryté služby v Tor síti.</translation>
+ <translation>Připojí se do bitcoinové sítě přes SOCKS5 proxy vyhrazenou pro skryté služby v Tor síti.</translation>
</message>
<message>
<source>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</source>
@@ -718,6 +1108,14 @@
<translation>O&amp;kno</translation>
</message>
<message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>Skryje ikonu, která se zobrazuje v panelu.</translation>
+ </message>
+ <message>
+ <source>Hide tray icon</source>
+ <translation>Skrýt &amp;ikonu z panelu</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation>Po minimalizaci okna zobrazí pouze ikonu v panelu.</translation>
</message>
@@ -738,6 +1136,10 @@
<translation>&amp;Jazyk uživatelského rozhraní:</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>Tady lze nastavit jazyk uživatelského rozhraní. Nastavení se projeví až po restartování %1.</translation>
+ </message>
+ <message>
<source>&amp;Unit to show amounts in:</source>
<translation>Je&amp;dnotka pro částky:</translation>
</message>
@@ -751,7 +1153,7 @@
</message>
<message>
<source>&amp;OK</source>
- <translation>&amp;Použít</translation>
+ <translation>&amp;Budiž</translation>
</message>
<message>
<source>&amp;Cancel</source>
@@ -779,7 +1181,7 @@
</message>
<message>
<source>This change would require a client restart.</source>
- <translation>Tato změna vyžaduje restart aplikace.</translation>
+ <translation>Tahle změna bude chtít restartovat klienta.</translation>
</message>
<message>
<source>The supplied proxy address is invalid.</source>
@@ -794,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>Zobrazené informace nemusí být aktuální. Tvá peněženka se automaticky sesynchronizuje s Bitcoinovou sítí, jakmile se s ní spojí. Zatím ale ještě není synchronizace dokončena.</translation>
+ <translation>Zobrazené informace nemusí být aktuální. Tvá peněženka se automaticky sesynchronizuje s bitcoinovou sítí, jakmile se s ní spojí. Zatím ale ještě není synchronizace dokončena.</translation>
</message>
<message>
<source>Watch-only:</source>
@@ -826,7 +1228,7 @@
</message>
<message>
<source>Balances</source>
- <translation>Stav účtů</translation>
+ <translation>Stavy účtů</translation>
</message>
<message>
<source>Total:</source>
@@ -862,6 +1264,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Chyba platebního požadavku</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Nemůžu spustit bitcoin: obsluha click-to-pay</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Zpracování URI</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>Zdrojová URL platebního požadavku není platná: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Neplatná platební adresa %1</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation>Nepodařilo se analyzovat URI! Důvodem může být neplatná bitcoinová adresa nebo poškozené parametry URI.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Zpracování souboru platebního požadavku</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>Soubor platebního požadavku nejde přečíst nebo zpracovat! Příčinou může být špatný soubor platebního požadavku.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Platební požadavek byl odmítnut</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Síť platebního požadavku neodpovídá síti klienta.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Platební požadavek vypršel.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Platební požadavek není zahájený.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Neověřené platební požadavky k uživatelským platebním skriptům nejsou podporované.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Neplatný platební požadavek.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Požadovaná platební částka %1 je příliš malá (je považována za prach).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Vrácení peněz od %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>Platební požadavek %1 je moc velký (%2 bajtů, povoleno %3 bajtů).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Chyba při komunikaci s %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Platební požadavek je nečitelný!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Chybná odpověď ze serveru %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Chyba síťového požadavku</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Platba potvrzena</translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -872,7 +1365,11 @@
<translation>Uzel/Služba</translation>
</message>
<message>
- <source>Ping Time</source>
+ <source>NodeId</source>
+ <translation>Id uzlu</translation>
+ </message>
+ <message>
+ <source>Ping</source>
<translation>Odezva</translation>
</message>
</context>
@@ -884,7 +1381,7 @@
</message>
<message>
<source>Enter a Bitcoin address (e.g. %1)</source>
- <translation>Zadej Bitcoinovou adresu (např. %1)</translation>
+ <translation>Zadej bitcoinovou adresu (např. %1)</translation>
</message>
<message>
<source>%1 d</source>
@@ -914,12 +1411,78 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n vteřinu</numerusform><numerusform>%n vteřiny</numerusform><numerusform>%n vteřin</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minutu</numerusform><numerusform>%n minuty</numerusform><numerusform>%n minut</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n hodinu</numerusform><numerusform>%n hodiny</numerusform><numerusform>%n hodin</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n den</numerusform><numerusform>%n dny</numerusform><numerusform>%n dnů</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n týden</numerusform><numerusform>%n týdny</numerusform><numerusform>%n týdnů</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 a %2</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n rok</numerusform><numerusform>%n roky</numerusform><numerusform>%n roků</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 ještě bezpečně neskončil…</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Chyba: Zadaný adresář pro data „%1“ neexistuje.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>Chyba: Nemohu zpracovat konfigurační soubor: %1. Používej pouze syntaxi klíč=hodnota.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Chyba: %1</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Ulož obrázek...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Kopíruj obrázek</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Ulož QR kód</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG obrázek (*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
<message>
<source>N/A</source>
- <translation>N/A</translation>
+ <translation>nedostupná informace</translation>
</message>
<message>
<source>Client version</source>
@@ -942,6 +1505,10 @@
<translation>Používaná verze BerkeleyDB</translation>
</message>
<message>
+ <source>Datadir</source>
+ <translation>Adresář s daty</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>Čas spuštění</translation>
</message>
@@ -966,8 +1533,16 @@
<translation>Aktuální počet bloků</translation>
</message>
<message>
+ <source>Memory Pool</source>
+ <translation>Transakční zásobník</translation>
+ </message>
+ <message>
+ <source>Current number of transactions</source>
+ <translation>Aktuální množství transakcí</translation>
+ </message>
+ <message>
<source>Memory usage</source>
- <translation>Využití paměti</translation>
+ <translation>Obsazenost paměti</translation>
</message>
<message>
<source>Received</source>
@@ -982,10 +1557,18 @@
<translation>&amp;Protějšky</translation>
</message>
<message>
+ <source>Banned peers</source>
+ <translation>Protějšky pod klatbou (blokované)</translation>
+ </message>
+ <message>
<source>Select a peer to view detailed information.</source>
<translation>Vyber protějšek a uvidíš jeho detailní informace.</translation>
</message>
<message>
+ <source>Whitelisted</source>
+ <translation>Vždy vítán</translation>
+ </message>
+ <message>
<source>Direction</source>
<translation>Směr</translation>
</message>
@@ -994,10 +1577,34 @@
<translation>Verze</translation>
</message>
<message>
+ <source>Starting Block</source>
+ <translation>Počáteční blok</translation>
+ </message>
+ <message>
+ <source>Synced Headers</source>
+ <translation>Aktuálně hlaviček</translation>
+ </message>
+ <message>
+ <source>Synced Blocks</source>
+ <translation>Aktuálně bloků</translation>
+ </message>
+ <message>
<source>User Agent</source>
<translation>Typ klienta</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>Otevři soubor s ladicími záznamy %1 z aktuálního datového adresáře. U velkých žurnálů to může pár vteřin zabrat.</translation>
+ </message>
+ <message>
+ <source>Decrease font size</source>
+ <translation>Zmenšit písmo</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation>Zvětšit písmo</translation>
+ </message>
+ <message>
<source>Services</source>
<translation>Služby</translation>
</message>
@@ -1022,6 +1629,18 @@
<translation>Odezva</translation>
</message>
<message>
+ <source>The duration of a currently outstanding ping.</source>
+ <translation>Jak dlouho už čekám na pong.</translation>
+ </message>
+ <message>
+ <source>Ping Wait</source>
+ <translation>Doba čekání na odezvu</translation>
+ </message>
+ <message>
+ <source>Min Ping</source>
+ <translation>Nejrychlejší odezva</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Časový posun</translation>
</message>
@@ -1066,14 +1685,6 @@
<translation>Vyčistit konzoli</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Odpojit uzel</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Uvalit na uzel klatbu na</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;hodinu</translation>
</message>
@@ -1090,8 +1701,20 @@
<translation>1 &amp;rok</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Zbavit uzel klatby</translation>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Odpoj</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Uval klatbu na</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Odblokuj</translation>
+ </message>
+ <message>
+ <source>Welcome to the %1 RPC console.</source>
+ <translation>Vítej v RPC konzoli %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>
@@ -1102,6 +1725,14 @@
<translation>Napsáním &lt;b&gt;help&lt;/b&gt; si vypíšeš přehled dostupných příkazů.</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>UPOZORNĚNÍ: Podvodníci jsou aktivní a říkají uživatelům, aby sem zadávali příkazy, kterými jim pak ale vykradou jejich peněženky. Nepoužívej tuhle konzoli, pokud úplně neznáš důsledky jednotlivých příkazů.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Síť je vypnutá</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1174,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>Volitelná zpráva, která se připojí k platebnímu požadavku a která se zobrazí, když se požadavek otevře. Poznámka: tahle zpráva se neposílá s platbou po Bitcoinové síti.</translation>
+ <translation>Volitelná zpráva, která se připojí k platebnímu požadavku a která se zobrazí, když se požadavek otevře. Poznámka: tahle zpráva se neposílá s platbou po bitcoinové síti.</translation>
</message>
<message>
<source>An optional label to associate with the new receiving address.</source>
@@ -1220,6 +1851,22 @@
<source>Remove</source>
<translation>Smazat</translation>
</message>
+ <message>
+ <source>Copy URI</source>
+ <translation>Kopíruj URI</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopíruj její označení</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Kopíruj zprávu</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopíruj částku</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1239,6 +1886,73 @@
<source>&amp;Save Image...</source>
<translation>&amp;Ulož obrázek...</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Platební požadavek: %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informace o platbě</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresa</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Částka</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Označení</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Zpráva</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>Výsledná URI je příliš dlouhá, zkus zkrátit text označení/zprávy.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Chyba při kódování URI do QR kódu.</translation>
+ </message>
+</context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Označení</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Zpráva</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(bez označení)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(bez zprávy)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(bez požadované částky)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Požádáno</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1275,10 +1989,6 @@
<translation>Částka:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorita:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Poplatek:</translation>
</message>
@@ -1347,10 +2057,6 @@
<translation>(Inteligentní poplatek ještě není inicializovaný. Obvykle mu to tak pár bloků trvá...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Rychlost potvrzení:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normální</translation>
</message>
@@ -1375,6 +2081,10 @@
<translation>Prach:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Časové cílování potvrzení:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Všechno s&amp;maž</translation>
</message>
@@ -1390,6 +2100,126 @@
<source>S&amp;end</source>
<translation>Pošl&amp;i</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopíruj počet</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopíruj částku</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopíruj poplatek</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopíruj čistou částku</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopíruj bajty</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopíruj prach</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopíruj drobné</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 pro %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Jsi si jistý, že to chceš poslat?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>přidán jako transakční poplatek</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Celková částka %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>nebo</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Potvrď odeslání mincí</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Adresa příjemce je neplatná – překontroluj ji prosím.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Odesílaná částka musí být větší než 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Částka překračuje stav účtu.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>Celková částka při připočítání poplatku %1 překročí stav účtu.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Zaznamenána duplicitní adresa: každá adresa by ale měla být použita vždy jen jednou.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Vytvoření transakce selhalo!</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>Transakce byla zamítnuta s tímto odůvodněním: %1</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Poplatek vyšší než %1 je považován za absurdně vysoký.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Platební požadavek vypršel.</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n blok</numerusform><numerusform>%n bloky</numerusform><numerusform>%n bloků</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Zaplatit pouze vyžadovaný poplatek %1</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Potvrzování by podle odhadu mělo začít během %n bloku.</numerusform><numerusform>Potvrzování by podle odhadu mělo začít během %n bloků.</numerusform><numerusform>Potvrzování by podle odhadu mělo začít během %n bloků.</numerusform></translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Upozornění: Neplatná bitcoinová adresa</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <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>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1459,7 +2289,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>Zpráva, která byla připojena k bitcoin: URI a která se ti pro přehled uloží k transakci. Poznámka: Tahle zpráva se neposílá s platbou po Bitcoinové síti.</translation>
+ <translation>Zpráva, která byla připojena k bitcoin: URI a která se ti pro přehled uloží k transakci. Poznámka: Tahle zpráva se neposílá s platbou po bitcoinové síti.</translation>
</message>
<message>
<source>Pay To:</source>
@@ -1469,10 +2299,25 @@
<source>Memo:</source>
<translation>Poznámka:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Zadej označení této adresy; obojí se ti pak uloží do adresáře</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Ano</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down...</source>
+ <translation>%1 se ukončuje...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation>Nevypínej počítač, dokud toto okno nezmizí.</translation>
</message>
@@ -1525,7 +2370,7 @@
</message>
<message>
<source>Sign the message to prove you own this Bitcoin address</source>
- <translation>Podepiš zprávu, čímž prokážeš, že jsi vlastníkem této Bitcoinové adresy</translation>
+ <translation>Podepiš zprávu, čímž prokážeš, že jsi vlastníkem této bitcoinové adresy</translation>
</message>
<message>
<source>Sign &amp;Message</source>
@@ -1553,7 +2398,7 @@
</message>
<message>
<source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
- <translation>Ověř zprávu, aby ses ujistil, že byla podepsána danou Bitcoinovou adresou</translation>
+ <translation>Ověř zprávu, aby ses ujistil, že byla podepsána danou bitcoinovou adresou</translation>
</message>
<message>
<source>Verify &amp;Message</source>
@@ -1563,6 +2408,58 @@
<source>Reset all verify message fields</source>
<translation>Vymaž všechna pole formuláře pro ověření zrávy</translation>
</message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Kliknutím na „Podepiš zprávu“ vygeneruješ podpis</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>Zkontroluj ji prosím a zkus to pak znovu.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>Zadaná adresa nepasuje ke klíči.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Odemčení peněženky bylo zrušeno.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Soukromý klíč pro zadanou adresu není dostupný.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Nepodařilo se podepsat zprávu.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Zpráva podepsána.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Podpis nejde dekódovat.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Zkontroluj ho prosím a zkus to pak znovu.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>Podpis se neshoduje s hašem zprávy.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Nepodařilo se ověřit zprávu.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Zpráva ověřena.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1579,11 +2476,460 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Otevřeno pro %n další blok</numerusform><numerusform>Otevřeno pro %n další bloky</numerusform><numerusform>Otevřeno pro %n dalších bloků</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Otřevřeno dokud %1</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>koliduje s transakcí o %1 konfirmacích</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/offline</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/nepotvrzeno, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>v transakčním zásobníku</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>není ani v transakčním zásobníku</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>zanechaná</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/nepotvrzeno</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 potvrzení</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Stav</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, ještě nebylo rozesláno</translation>
+ </message>
+ <message numerus="yes">
+ <source>, broadcast through %n node(s)</source>
+ <translation><numerusform>, rozesláno přes %n uzel</numerusform><numerusform>, rozesláno přes %n uzly</numerusform><numerusform>, rozesláno přes %n uzlů</numerusform></translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Zdroj</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Vygenerováno</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Od</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>neznámo</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Pro</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>vlastní adresa</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>sledovaná</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>označení</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Příjem</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>dozraje po %n bloku</numerusform><numerusform>dozraje po %n blocích</numerusform><numerusform>dozraje po %n blocích</numerusform></translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>neakceptováno</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Výdaj</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Celkové výdaje</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Celkové příjmy</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Transakční poplatek</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Čistá částka</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Zpráva</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Komentář</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>ID transakce</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation>Celková velikost transakce</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Pořadí výstupu</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Obchodník</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>Vygenerované mince musí čekat %1 bloků, než mohou být utraceny. Když jsi vygeneroval tenhle blok, tak byl rozposlán do sítě, aby byl přidán do řetězce bloků. Pokud se mu nepodaří dostat se do řetězce, změní se na „neakceptovaný“ a nepůjde utratit. To se občas může stát, pokud jiný uzel vygeneruje blok zhruba ve stejném okamžiku jako ty.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Ladicí informace</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transakce</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Vstupy</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Částka</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>true</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>false</translation>
+ </message>
+</context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Toto okno zobrazuje detailní popis transakce</translation>
</message>
+ <message>
+ <source>Details for %1</source>
+ <translation>Podrobnosti o %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>Označení</translation>
+ </message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Otevřeno pro %n další blok</numerusform><numerusform>Otevřeno pro %n další bloky</numerusform><numerusform>Otevřeno pro %n dalších bloků</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Otřevřeno dokud %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Offline</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Nepotvrzeno</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Zanechaná</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Potvrzuje se (%1 z %2 doporučených potvrzení)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Potvrzeno (%1 potvrzení)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>V kolizi</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Nedozráno (%1 potvrzení, dozraje při %2 potvrzeních)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Tento blok nedostal žádný jiný uzel a pravděpodobně nebude akceptován!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Vygenerováno, ale neakceptováno</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Přijato do</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Přijato od</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Posláno na</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Platba sama sobě</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Vytěženo</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>sledovací</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/a)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(bez označení)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Stav transakce. Najetím myši na toto políčko si zobrazíš počet potvrzení.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Datum a čas přijetí transakce.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Druh transakce.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Zda tato transakce zahrnuje i některou sledovanou adresu.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Uživatelsky určený účel transakce.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Částka odečtená z nebo přičtená k účtu.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Vše</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Dnes</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Tento týden</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Tento měsíc</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Minulý měsíc</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Letos</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Rozsah...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Přijato</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Posláno</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Sám sobě</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Vytěženo</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Ostatní</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Zadej adresu nebo označení pro její vyhledání</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Minimální částka</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Zapomenout transakci</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopíruj adresu</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopíruj její označení</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopíruj částku</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopíruj ID transakce</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Kopíruj surovou transakci</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Kopíruj kompletní podrobnosti o transakci</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Uprav označení</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Zobraz detaily transakce</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exportuj transakční historii</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Formát CSV (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Potvrzeno</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Sledovaná</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Typ</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Označení</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresa</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Exportování selhalo</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Při ukládání transakční historie do %1 se přihodila nějaká chyba.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Úspěšně vyexportováno</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>Transakční historie byla v pořádku uložena do %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Rozsah:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>až</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1593,6 +2939,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Žádná peněženka se nenačetla.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Pošli mince</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Export</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Exportuj data z tohoto panelu do souboru</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Záloha peněženky</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Data peněženky (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Zálohování selhalo</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Při ukládání peněženky do %1 se přihodila nějaká chyba.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Úspěšně zazálohováno</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Data z peněženky byla v pořádku uložena do %1.</translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1615,6 +3010,18 @@
<translation>Akceptovat příkazy z příkazové řádky a přes JSON-RPC</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>Přijímat spojení zvenčí (výchozí: 1, pokud není zadáno -proxy nebo -connect/-noconnect)</translation>
+ </message>
+ <message>
+ <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
+ <translation>Připojovat se pouze k určeným uzlům; samotné -noconnect nebo -connect=0 zakáží automatické připojování</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>Šířen pod softwarovou licencí MIT, viz přiložený soubor %s nebo %s</translation>
+ </message>
+ <message>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation>Pokud není &lt;category&gt; zadána nebo je &lt;category&gt; = 1, bude tisknout veškeré ladicí informace.</translation>
</message>
@@ -1627,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>
@@ -1655,16 +3058,12 @@
<translation>Nemohu spustit HTTP server. Detaily viz v debug.log.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Přijímat spojení zvenčí (výchozí: 1, pokud není zadáno -proxy nebo -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee je nastaveno velmi vysoko! Toto je transakční poplatek, který bys platil, pokud nebude k dispozici odhad poplatků.</translation>
+ <source>The %s developers</source>
+ <translation>Vývojáři %s</translation>
</message>
<message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
@@ -1679,20 +3078,56 @@
<translation>Poslouchat na zadané adrese. Pro zápis IPv6 adresy použij notaci [adresa]:port</translation>
</message>
<message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation>Nedaří se mi získat zámek na datový adresář %s. %s pravděpodobně už jednou běží.</translation>
+ </message>
+ <message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation>Smazat všechny transakce peněženky a při startu obnovit pouze relevantní části řetězce bloků pomocí -rescan</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Šířen pod softwarovou licencí MIT, viz přiložený soubor COPYING nebo &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
+ <source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
+ <translation>Chyba při načítání %s: nemůžeš zapnout HD u existující ne-HD peněženky</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>Nastala chyba při čtení souboru %s! Všechny klíče se přečetly správně, ale data o transakcích nebo záznamy v adresáři mohou chybět či být nesprávné.</translation>
</message>
<message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<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>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Vynutit přeposílání transakcí od vždy vítaných protějšků (tj. těch na bílé listině), i když porušují místní zásady pro přeposílání (výchozí: %d)</translation>
+ <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>
+ <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>Horní hranice pro celkový poplatek (v %s) za jednu transakci z peněženky nebo jednu surovou transakci; příliš nízká hodnota může zmařit velké transakce (výchozí: %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>
+ <translation>Zkontroluj, že máš v počítači správně nastavený datum a čas! Pokud jsou nastaveny špatně, %s nebude fungovat správně.</translation>
+ </message>
+ <message>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
+ <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>
@@ -1707,10 +3142,22 @@
<translation>Tohle je testovací verze – používej ji jen na vlastní riziko, ale rozhodně ji nepoužívej k těžbě nebo pro obchodní aplikace</translation>
</message>
<message>
+ <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
+ <translation>Nedaří se mi vrátit databázi do stavu před štěpem. Budeš muset znovu stáhnout celý řetězec bloků</translation>
+ </message>
+ <message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<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>
+ <message>
<source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
<translation>Upozornění: Síť podle všeho není v konzistentním stavu. Někteří těžaři jsou zřejmě v potížích.</translation>
</message>
@@ -1719,8 +3166,12 @@
<translation>Upozornění: Nesouhlasím zcela se svými protějšky! Možná potřebuji aktualizovat nebo ostatní uzly potřebují aktualizovat.</translation>
</message>
<message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Vždy vítat protějšky připojující se z dané podsítě či IP adresy. Lze zadat i vícekrát.</translation>
+ <source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
+ <translation>Je třeba přestavět databázi použitím -reindex-chainstate, aby bylo možné změnit -txindex</translation>
+ </message>
+ <message>
+ <source>%s corrupt, salvage failed</source>
+ <translation>%s je poškozen, jeho záchrana se nezdařila</translation>
</message>
<message>
<source>-maxmempool must be at least %d MB</source>
@@ -1735,18 +3186,34 @@
<translation>Připojit komentář k typu klienta</translation>
</message>
<message>
+ <source>Attempt to recover private keys from a corrupt wallet on startup</source>
+ <translation>Pokusit se při startu zachránit soukromé klíče z poškozeného souboru s klíči</translation>
+ </message>
+ <message>
<source>Block creation options:</source>
<translation>Možnosti vytváření bloku:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Připojit se pouze k zadanému uzlu (příp. zadaným uzlům)</translation>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>Nemohu přeložit -%s adresu: '%s'</translation>
+ </message>
+ <message>
+ <source>Chain selection options:</source>
+ <translation>Možnosti výběru řetězce:</translation>
+ </message>
+ <message>
+ <source>Change index out of range</source>
+ <translation>Index drobných je mimo platný rozsah</translation>
</message>
<message>
<source>Connection options:</source>
<translation>Možnosti připojení:</translation>
</message>
<message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Copyright (C) %i–%i</translation>
+ </message>
+ <message>
<source>Corrupted block database detected</source>
<translation>Bylo zjištěno poškození databáze bloků</translation>
</message>
@@ -1763,6 +3230,26 @@
<translation>Chceš přestavět databázi bloků hned teď?</translation>
</message>
<message>
+ <source>Enable publish hash block in &lt;address&gt;</source>
+ <translation>Zapnout oznamování hashů bloků na adrese &lt;address&gt;</translation>
+ </message>
+ <message>
+ <source>Enable publish hash transaction in &lt;address&gt;</source>
+ <translation>Zapnout oznamování hashů transakcí na adrese &lt;address&gt;</translation>
+ </message>
+ <message>
+ <source>Enable publish raw block in &lt;address&gt;</source>
+ <translation>Zapnout oznamování surových bloků na adrese &lt;address&gt;</translation>
+ </message>
+ <message>
+ <source>Enable publish raw transaction in &lt;address&gt;</source>
+ <translation>Zapnout oznamování surových transakcí na adrese &lt;address&gt;</translation>
+ </message>
+ <message>
+ <source>Enable transaction replacement in the memory pool (default: %u)</source>
+ <translation>Povolit výměnu transakcí v transakčním zásobníku (výchozí: %u)</translation>
+ </message>
+ <message>
<source>Error initializing block database</source>
<translation>Chyba při zakládání databáze bloků</translation>
</message>
@@ -1771,6 +3258,22 @@
<translation>Chyba při vytváření databázového prostředí %s pro peněženku!</translation>
</message>
<message>
+ <source>Error loading %s</source>
+ <translation>Chyba při načítání %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation>Chyba při načítání %s: peněženka je poškozená</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation>Chyba při načítání %s: peněženka vyžaduje novější verzi %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: You can't disable HD on a already existing HD wallet</source>
+ <translation>Chyba při načítání %s: nemůžeš vypnout HD u existující HD peněženky</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>Chyba při načítání databáze bloků</translation>
</message>
@@ -1795,10 +3298,18 @@
<translation>Nemám žádný nebo jen špatný genesis blok. Není špatně nastavený datadir?</translation>
</message>
<message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation>Selhala úvodní zevrubná prověrka. %s se ukončuje.</translation>
+ </message>
+ <message>
<source>Invalid -onion address: '%s'</source>
<translation>Neplatná -onion adresa: '%s'</translation>
</message>
<message>
+ <source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
+ <translation>Neplatná částka pro -%s=&lt;částka&gt;: '%s'</translation>
+ </message>
+ <message>
<source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
<translation>Neplatná částka pro -fallbackfee=&lt;částka&gt;: '%s'</translation>
</message>
@@ -1807,12 +3318,12 @@
<translation>Udržovat zasobník transakcí menší než &lt;n&gt; megabajtů (výchozí: %u)</translation>
</message>
<message>
- <source>Location of the auth cookie (default: data dir)</source>
- <translation>Místo pro autentizační cookie (výchozí: adresář pro data)</translation>
+ <source>Loading banlist...</source>
+ <translation>Načítám seznam klateb...</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>Minimální počet bajtů na každý sigop v transakcích, které přeposíláme a těžíme (výchozí: %u)</translation>
+ <source>Location of the auth cookie (default: data dir)</source>
+ <translation>Místo pro autentizační cookie (výchozí: adresář pro data)</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -1823,6 +3334,10 @@
<translation>Připojovat se pouze k uzlům v &lt;net&gt; síti (ipv4, ipv6 nebo onion)</translation>
</message>
<message>
+ <source>Print this help message and exit</source>
+ <translation>Vypsat tuto nápovědu a skončit</translation>
+ </message>
+ <message>
<source>Print version and exit</source>
<translation>Vypsat verzi a skončit</translation>
</message>
@@ -1835,6 +3350,18 @@
<translation>Prořezávací režim není kompatibilní s -txindex.</translation>
</message>
<message>
+ <source>Rebuild chain state and block index from the blk*.dat files on disk</source>
+ <translation>Při startu znovu vytvořit index řetězce bloků z aktuálních blk*.dat souborů</translation>
+ </message>
+ <message>
+ <source>Rebuild chain state from the currently indexed blocks</source>
+ <translation>Znovu vytvořit stav řetězce bloků z aktuálně indexovaných bloků</translation>
+ </message>
+ <message>
+ <source>Rewinding blocks...</source>
+ <translation>Vracím bloky…</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>Nastavit velikost databázové vyrovnávací paměti v megabajtech (%d až %d, výchozí: %d)</translation>
</message>
@@ -1847,6 +3374,14 @@
<translation>Udej název souboru s peněženkou (v rámci datového adresáře)</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation>Zdrojový kód je dostupný na %s.</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation>Nedaří se mi připojit na %s na tomhle počítači. %s už pravděpodobně jednou běží.</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Nepodporovaný argument -benchmark se ignoruje, použij -debug=bench.</translation>
</message>
@@ -1863,22 +3398,34 @@
<translation>Použít UPnP k namapování naslouchacího portu (výchozí: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Použít testovací řetězec</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>Komentář u typu klienta (%s) obsahuje riskantní znaky.</translation>
</message>
<message>
<source>Verifying blocks...</source>
- <translation>Ověřuji bloky...</translation>
+ <translation>Ověřuji bloky…</translation>
</message>
<message>
<source>Verifying wallet...</source>
- <translation>Kontroluji peněženku...</translation>
+ <translation>Kontroluji peněženku…</translation>
</message>
<message>
<source>Wallet %s resides outside data directory %s</source>
<translation>Peněženka %s se nachází mimo datový adresář %s</translation>
</message>
<message>
+ <source>Wallet debugging/testing options:</source>
+ <translation>Možnosti ladění/testování peněženky:</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>Soubor s peněženkou potřeboval přepsat: restartuj %s, aby se operace dokončila</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Možnosti peněženky:</translation>
</message>
@@ -1927,10 +3474,6 @@
<translation>Maximální velikost dat v transakcích nesoucích data, se kterou jsme ochotni je ještě přeposílat a těžit (výchozí: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Při nedostatku adres získat další protějšky z DNS (výchozí: 1, pokud není použito -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Použít náhodné údaje pro každé proxy spojení. To umožní izolovat nesouvisející datové toky v Toru (výchozí: %u)</translation>
</message>
@@ -1943,8 +3486,8 @@
<translation>Částka v transakci po odečtení poplatku je příliš malá na odeslání</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v OpenSSL Toolkitu &lt;https://www.openssl.org/&gt; a kryptografický program od Erika Younga a program UPnP od Thomase Bernarda.</translation>
+ <source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
+ <translation>Použít hierarchické deterministické generování klíčů (HD) podle BIP32. Má vliv pouze během vytváření peněženky/prvního 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>
@@ -2055,10 +3598,6 @@
<translation>Částka v transakci je příliš malá</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Částky v transakci musí být kladné</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transakce je na poplatkovou politiku příliš velká</translation>
</message>
@@ -2083,6 +3622,10 @@
<translation>Upozornění</translation>
</message>
<message>
+ <source>Warning: unknown new rules activated (versionbit %i)</source>
+ <translation>Upozornění: aktivována neznámá nová pravidla (verzový bit %i)</translation>
+ </message>
+ <message>
<source>Whether to operate in a blocks only mode (default: %u)</source>
<translation>Zda fungovat v čistě blokovém režimu (výchozí: %u)</translation>
</message>
@@ -2092,7 +3635,7 @@
</message>
<message>
<source>ZeroMQ notification options:</source>
- <translation>Možnosti ZeroMQ oznámení:</translation>
+ <translation>Možnosti ZeroMQ oznamování:</translation>
</message>
<message>
<source>Password for JSON-RPC connections</source>
@@ -2119,18 +3662,22 @@
<translation>-maxtxfee je nastaveno velmi vysoko! Takto vysoký poplatek může být zaplacen v jednotlivé transakci.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee je nastaveno velmi vysoko! Toto je transakční poplatek, který zaplatíš za každou poslanou transakci.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Nedržet transakce v zásobníku déle než &lt;n&gt; hodin (výchozí: %u)</translation>
</message>
<message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Ekvivalent bajtů za každý sigop v transakcích – pro účely přeposílání a těžení (výchozí: %u)</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ší než tato hodnota jsou považovány za nulové pro účely vytváření transakcí (výchozí: %s)</translation>
</message>
<message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>Vynutit přeposílání transakcí od vždy vítaných protějšků (tj. těch na bílé listině), i když porušují místní zásady pro přeposílání (výchozí: %d)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>Jak moc důkladná má být verifikace bloků -checkblocks (0-4, výchozí: %u)</translation>
</message>
@@ -2147,10 +3694,26 @@
<translation>Tisknout ladicí informace (výchozí: %u, zadání &lt;category&gt; je volitelné)</translation>
</message>
<message>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
+ <translation>Při nedostatku adres získat další protějšky z DNS (výchozí: 1, pokud není použito -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>Nastaví serializaci surových transakcí nebo bloků, jak jsou vraceny v méně povídavém módu: ne-segwit (0) nebo segwit (1) (výchozí: %d)</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation>Umožnit filtrování bloků a transakcí pomocí Bloomova filtru (výchozí: %u)</translation>
</message>
<message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Toto je transakční poplatek, který se platí, pokud náhodou není k dispozici odhad poplatků.</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>Tento produkt zahrnuje programy vyvinuté OpenSSL Projektem pro použití v OpenSSL Toolkitu %s a kryptografický program od Erika Younga a program UPnP od Thomase Bernarda.</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élka síťového identifikačního řetězce (%i) překročila svůj horní limit (%i). Omez počet nebo velikost voleb uacomment.</translation>
</message>
@@ -2171,8 +3734,20 @@
<translation>Použít samostatnou SOCKS5 proxy ke spojení s protějšky přes skryté služby v Toru (výchozí: %s)</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. 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. Tuto volbu lze použít i vícekrát</translation>
+ <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
+ <translation>Upozornění: Síť těží neznámé verze bloků! Je možné, že jsou v platnosti neznámá pravidla</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>Upozornění: soubor s peněženkou je poškozený, data jsou však zachráněna! Původní soubor %s je uložený jako %s v %s. Pokud nejsou stav tvého účtu nebo transakce v pořádku, zřejmě bys měl obnovit 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>Vždy vítat protějšky připojující se z dané IP adresy (např. 1.2.3.4) či podsítě (CIDR zápis, např. 1.2.3.0/24). Lze zadat i vícekrát.</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation>%s je nastaveno velmi vysoko!</translation>
</message>
<message>
<source>(default: %s)</source>
@@ -2195,6 +3770,10 @@
<translation>Neplatná -proxy adresa: '%s'</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Vyčerpal se zásobník klíčů, zavolej prvně, prosím, keypoolrefill</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>Čekat na JSON-RPC spojení na &lt;portu&gt; (výchozí: %u nebo testnet: %u)</translation>
</message>
@@ -2231,12 +3810,16 @@
<translation>Přeposílat ne-P2SH multisig (výchozí: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>Posílat transakce se zapnutým plným RBF (= replace-by-fee) (výchozí: %u)</translation>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation>Nastavit zásobník klíčů na velikost &lt;n&gt; (výchozí: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Nastavit minimální velikost bloku v bajtech (výchozí: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Nastavit maximální váhu bloku pro BIP141 (výchozí: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
@@ -2255,10 +3838,38 @@
<translation>Utrácet i ještě nepotvrzené drobné při posílání transakcí (výchozí: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Spouštím síťová vlákna…</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>Peněženka zaručí přiložení poplatku alespoň ve výši minima pro přenos transakce.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Toto je minimální poplatek, který zaplatíš za každou transakci.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Toto je poplatek, který zaplatíš za každou poslanou transakci.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Práh pro odpojování zlobivých protějšků (výchozí: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Částky v transakci nemohou být záporné</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>Transakce má v transakčním zásobníku příliš dlouhý řetězec</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>Transakce musí mít alespoň jednoho příjemce</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>V -onlynet byla uvedena neznámá síť: '%s'</translation>
</message>
@@ -2288,7 +3899,7 @@
</message>
<message>
<source>Rescanning...</source>
- <translation>Přeskenovávám...</translation>
+ <translation>Přeskenovávám…</translation>
</message>
<message>
<source>Done loading</source>
diff --git a/src/qt/locale/bitcoin_cs_CZ.ts b/src/qt/locale/bitcoin_cs_CZ.ts
deleted file mode 100644
index 70aa981f50..0000000000
--- a/src/qt/locale/bitcoin_cs_CZ.ts
+++ /dev/null
@@ -1,300 +0,0 @@
-<TS language="cs_CZ" version="2.1">
-<context>
- <name>AddressBookPage</name>
- <message>
- <source>Right-click to edit address or label</source>
- <translation>Pravým klikem editujte adresu nebo popisek</translation>
- </message>
- <message>
- <source>Create a new address</source>
- <translation>Vytvořit novou adresu</translation>
- </message>
- <message>
- <source>Copy the currently selected address to the system clipboard</source>
- <translation>Kopírovat aktuálně vybrané adresy do schránky</translation>
- </message>
- <message>
- <source>Delete the currently selected address from the list</source>
- <translation>Odstraní aktuálně vybrané adresy ze seznamu</translation>
- </message>
- <message>
- <source>Export the data in the current tab to a file</source>
- <translation>Exportovat aktuální pohled do souboru</translation>
- </message>
- <message>
- <source>&amp;Export</source>
- <translation>&amp;Exportovat</translation>
- </message>
- <message>
- <source>&amp;Delete</source>
- <translation>&amp;Odstranit</translation>
- </message>
-</context>
-<context>
- <name>AskPassphraseDialog</name>
- <message>
- <source>Enter passphrase</source>
- <translation>Zadej heslo</translation>
- </message>
- <message>
- <source>New passphrase</source>
- <translation>Nové heslo</translation>
- </message>
- <message>
- <source>Repeat new passphrase</source>
- <translation>Zopakujte nové heslo</translation>
- </message>
-</context>
-<context>
- <name>BanTableModel</name>
- </context>
-<context>
- <name>BitcoinGUI</name>
- <message>
- <source>Synchronizing with network...</source>
- <translation>Synchronizuji se sítí...</translation>
- </message>
- <message>
- <source>&amp;Overview</source>
- <translation>&amp;Přehled</translation>
- </message>
- <message>
- <source>Show general overview of wallet</source>
- <translation>Zobrazit základní přehled o peněžence</translation>
- </message>
- <message>
- <source>&amp;Transactions</source>
- <translation>&amp;Transakce</translation>
- </message>
- <message>
- <source>Browse transaction history</source>
- <translation>Procházení historií transakcí</translation>
- </message>
- <message>
- <source>Quit application</source>
- <translation>Ukončit aplikaci</translation>
- </message>
- <message>
- <source>&amp;Options...</source>
- <translation>&amp;Možnosti...</translation>
- </message>
- <message>
- <source>Change the passphrase used for wallet encryption</source>
- <translation>Změnit heslo k šifrování peněženky</translation>
- </message>
- <message>
- <source>Bitcoin</source>
- <translation>Bitcoin</translation>
- </message>
- <message>
- <source>&amp;File</source>
- <translation>&amp;Soubor</translation>
- </message>
- <message>
- <source>&amp;Settings</source>
- <translation>&amp;Nastavení</translation>
- </message>
- <message>
- <source>&amp;Help</source>
- <translation>Nápo&amp;věda</translation>
- </message>
- <message>
- <source>Tabs toolbar</source>
- <translation>Panely</translation>
- </message>
- <message>
- <source>Up to date</source>
- <translation>Aktuální</translation>
- </message>
- <message>
- <source>Catching up...</source>
- <translation>Zachytávám...</translation>
- </message>
- <message>
- <source>Sent transaction</source>
- <translation>Odeslané transakce</translation>
- </message>
- <message>
- <source>Incoming transaction</source>
- <translation>Příchozí transakce</translation>
- </message>
- <message>
- <source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
- <translation>Peněženka je &lt;b&gt;zašifrována&lt;/b&gt; a momentálně &lt;b&gt;odemčená&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>Peněženka je &lt;b&gt;zašifrována&lt;/b&gt; a momentálně &lt;b&gt;uzamčená&lt;/b&gt;</translation>
- </message>
-</context>
-<context>
- <name>CoinControlDialog</name>
- <message>
- <source>Amount:</source>
- <translation>Množství:</translation>
- </message>
- <message>
- <source>Amount</source>
- <translation>Množství</translation>
- </message>
- <message>
- <source>Date</source>
- <translation>Datum</translation>
- </message>
- <message>
- <source>Confirmed</source>
- <translation>Potvrzeno</translation>
- </message>
- </context>
-<context>
- <name>EditAddressDialog</name>
- <message>
- <source>Edit Address</source>
- <translation>Upravit adresu</translation>
- </message>
- <message>
- <source>&amp;Label</source>
- <translation>&amp;Popisek</translation>
- </message>
- <message>
- <source>&amp;Address</source>
- <translation>&amp;Adresa</translation>
- </message>
-</context>
-<context>
- <name>FreespaceChecker</name>
- </context>
-<context>
- <name>HelpMessageDialog</name>
- <message>
- <source>Usage:</source>
- <translation>Použití:</translation>
- </message>
- </context>
-<context>
- <name>Intro</name>
- </context>
-<context>
- <name>OpenURIDialog</name>
- </context>
-<context>
- <name>OptionsDialog</name>
- <message>
- <source>Options</source>
- <translation>Možnosti</translation>
- </message>
- <message>
- <source>Map port using &amp;UPnP</source>
- <translation>Mapovat port pomocí &amp;UPnP</translation>
- </message>
- <message>
- <source>&amp;Minimize to the tray instead of the taskbar</source>
- <translation>&amp;Minimalizovat do systémové lišty (tray) namísto do hlavního panelu</translation>
- </message>
- <message>
- <source>M&amp;inimize on close</source>
- <translation>M&amp;inimalizovat při zavření</translation>
- </message>
- </context>
-<context>
- <name>OverviewPage</name>
- </context>
-<context>
- <name>PeerTableModel</name>
- </context>
-<context>
- <name>QObject</name>
- <message>
- <source>Amount</source>
- <translation>Množství</translation>
- </message>
- </context>
-<context>
- <name>RPCConsole</name>
- <message>
- <source>Name</source>
- <translation>Jméno</translation>
- </message>
- </context>
-<context>
- <name>ReceiveCoinsDialog</name>
- <message>
- <source>&amp;Label:</source>
- <translation>&amp;Popisek:</translation>
- </message>
- <message>
- <source>&amp;Message:</source>
- <translation>Zpráva:</translation>
- </message>
- </context>
-<context>
- <name>ReceiveRequestDialog</name>
- </context>
-<context>
- <name>SendCoinsDialog</name>
- <message>
- <source>Amount:</source>
- <translation>Množství:</translation>
- </message>
- <message>
- <source>Balance:</source>
- <translation>Zůstatek:</translation>
- </message>
- </context>
-<context>
- <name>SendCoinsEntry</name>
- <message>
- <source>&amp;Label:</source>
- <translation>&amp;Popisek:</translation>
- </message>
- <message>
- <source>Message:</source>
- <translation>Zpráva:</translation>
- </message>
- </context>
-<context>
- <name>ShutdownWindow</name>
- </context>
-<context>
- <name>SignVerifyMessageDialog</name>
- </context>
-<context>
- <name>SplashScreen</name>
- <message>
- <source>[testnet]</source>
- <translation>[testnet]</translation>
- </message>
-</context>
-<context>
- <name>TrafficGraphWidget</name>
- </context>
-<context>
- <name>TransactionDescDialog</name>
- <message>
- <source>This pane shows a detailed description of the transaction</source>
- <translation>Toto podokno zobrazuje detailní popis transakce</translation>
- </message>
-</context>
-<context>
- <name>UnitDisplayStatusBarControl</name>
- </context>
-<context>
- <name>bitcoin-core</name>
- <message>
- <source>Options:</source>
- <translation>Možnosti:</translation>
- </message>
- <message>
- <source>Loading addresses...</source>
- <translation>Načítání adres...</translation>
- </message>
- <message>
- <source>Loading wallet...</source>
- <translation>Načítání peněženky...</translation>
- </message>
- <message>
- <source>Done loading</source>
- <translation>Načítání dokončeno</translation>
- </message>
- </context>
-</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts
index 38bc45775b..9f2d87b606 100644
--- a/src/qt/locale/bitcoin_cy.ts
+++ b/src/qt/locale/bitcoin_cy.ts
@@ -29,7 +29,10 @@
<source>&amp;Delete</source>
<translation>&amp;Dileu</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -44,7 +47,7 @@
<source>Repeat new passphrase</source>
<translation>Ailadroddwch gyfrinymadrodd newydd</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -146,26 +149,6 @@
<source>Tabs toolbar</source>
<translation>Bar offer tabiau</translation>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n awr</numerusform><numerusform>%n awr</numerusform><numerusform>%n awr</numerusform><numerusform>%n awr</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n dydd</numerusform><numerusform>%n dydd</numerusform><numerusform>%n dydd</numerusform><numerusform>%n dydd</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n wythnos</numerusform><numerusform>%n wythnos</numerusform><numerusform>%n wythnos</numerusform><numerusform>%n wythnos</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 a %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n blwydd</numerusform><numerusform>%n blwydd</numerusform><numerusform>%n blwydd</numerusform><numerusform>%n blwydd</numerusform></translation>
- </message>
<message>
<source>Error</source>
<translation>Gwall</translation>
@@ -226,7 +209,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Mae'r waled &lt;b&gt;wedi'i amgryptio&lt;/b&gt; ac &lt;b&gt;ar glo&lt;/b&gt; ar hyn o bryd</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -252,7 +235,7 @@
<source>&amp;Address</source>
<translation>&amp;Cyfeiriad</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -279,6 +262,13 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Ffurflen</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -332,10 +322,23 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 a %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -367,6 +370,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -417,6 +423,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -445,12 +454,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts
index d298c81bd4..54ef4a2bdf 100644
--- a/src/qt/locale/bitcoin_da.ts
+++ b/src/qt/locale/bitcoin_da.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Slet</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Vælg adresse at sende bitcoins til</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Vælg adresse at modtage bitcoins med</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Vælg</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Afsendelsesadresser</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Modtagelsesadresser</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>Disse er dine Bitcoin-adresser til afsendelse af betalinger. Tjek altid beløb og modtagelsesadresse, inden du sender bitcoins.</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 til modtagelse af betalinger. Det anbefales at bruge en ny modtagelsesadresse for hver transaktion.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopiér adresse</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopiér &amp;mærkat</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Redigér</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Eksportér adresseliste</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kommasepareret fil (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksport mislykkedes</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Der opstod en fejl under gemning af adresselisten til %1. Prøv venligst igen.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Mærkat</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ingen mærkat)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>Gentag ny adgangskode</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>Indtast det nye kodeord til tegnebogen.&lt;br/&gt;Brug venligst et kodeord på &lt;b&gt;ti eller flere tilfældige tegn&lt;/b&gt; eller &lt;b&gt;otte eller flere ord&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Kryptér tegnebog</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Denne funktion har brug for din tegnebogs adgangskode for at låse tegnebogen op.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Lås tegnebog op</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Denne funktion har brug for din tegnebogs adgangskode for at dekryptere tegnebogen.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dekryptér tegnebog</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Skift adgangskode</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Indtast den gamle adgangskode og en ny adgangskode til tegnebogen.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Bekræft tegnebogskryptering</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 din tegnebog og mister din adgangskode, 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 ønsker at kryptere din tegnebog?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Tegnebog krypteret</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 nu lukke for at færdiggøre krypteringsprocessen. Husk at kryptering af din tegnebog kan ikke beskytte dine bitcoin fuldt ud mod at blive stjålet af eventuel malware, der måtte have inficeret din computer.</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>VIGTIGT: Enhver tidligere sikkerhedskopi, som du har lavet af tegnebogsfilen, bør blive erstattet af den nyligt genererede, krypterede tegnebogsfil. Af sikkerhedsmæssige årsager vil tidligere sikkerhedskopier af den ikke-krypterede tegnebogsfil blive ubrugelige i det øjeblik, du starter med at anvende den nye, krypterede tegnebog.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Tegnebogskryptering mislykkedes</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Tegnebogskryptering mislykkedes på grund af en intern fejl. Din tegnebog blev ikke krypteret.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>De angivne adgangskoder stemmer ikke overens.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Tegnebogsoplåsning mislykkedes</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Den angivne adgangskode for tegnebogsdekrypteringen er forkert.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Tegnebogsdekryptering mislykkedes</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Tegnebogens adgangskode blev ændret.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Advarsel: Caps Lock-tasten er aktiveret!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -76,7 +235,7 @@
<name>BitcoinGUI</name>
<message>
<source>Sign &amp;message...</source>
- <translation>Underskriv &amp;besked…</translation>
+ <translation>Signér &amp;besked…</translation>
</message>
<message>
<source>Synchronizing with network...</source>
@@ -159,6 +318,22 @@
<translation>&amp;Åbn URI…</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Klik for at deaktivere netværksaktivitet.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Netværksaktivitet deaktiveret.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <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>
@@ -216,11 +391,11 @@
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation>Underskriv beskeder med dine Bitcoin-adresser for at bevise, at de tilhører dig</translation>
+ <translation>Signér beskeder med dine Bitcoin-adresser for at bevise, at de tilhører dig</translation>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation>Verificér beskeder for at sikre, at de er underskrevet med de angivne Bitcoin-adresser</translation>
+ <translation>Verificér beskeder for at sikre, at de er signeret med de angivne Bitcoin-adresser</translation>
</message>
<message>
<source>&amp;File</source>
@@ -240,7 +415,7 @@
</message>
<message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation>Anmod om betalinger (genererer QR-koder og "bitcoin:"-URI'er)</translation>
+ <translation>Anmod om betalinger (genererer QR-koder og “bitcoin:”-URI'er)</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
@@ -252,7 +427,7 @@
</message>
<message>
<source>Open a bitcoin: URI or payment request</source>
- <translation>Åbn en "bitcoin:"-URI eller betalingsanmodning</translation>
+ <translation>Åbn en “bitcoin:”-URI eller betalingsanmodning</translation>
</message>
<message>
<source>&amp;Command-line options</source>
@@ -270,34 +445,10 @@
<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>
</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 dage</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n uge</numerusform><numerusform>%n uger</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>
<message>
<source>%1 behind</source>
<translation>%1 bagud</translation>
@@ -335,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>
@@ -377,6 +532,14 @@
<translation>Indgående transaktion</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>Generering af HD-nøgler er &lt;b&gt;aktiveret&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>Generering af HD-nøgler er &lt;b&gt;deaktiveret&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>Tegnebog er &lt;b&gt;krypteret&lt;/b&gt; og i øjeblikket &lt;b&gt;ulåst&lt;/b&gt;</translation>
</message>
@@ -384,6 +547,10 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Tegnebog er &lt;b&gt;krypteret&lt;/b&gt; og i øjeblikket &lt;b&gt;låst&lt;/b&gt;</translation>
</message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Der opstod en fatal fejl. Bitcoin kan ikke længere fortsætte sikkert og vil afslutte.</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -404,10 +571,6 @@
<translation>Beløb:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritet:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Gebyr:</translation>
</message>
@@ -460,8 +623,84 @@
<translation>Bekræftet</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Prioritet</translation>
+ <source>Copy address</source>
+ <translation>Kopiér adresse</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiér mærkat</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiér beløb</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopiér transaktions-ID</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Fastlås ubrugte</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Lås ubrugte op</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopiér mængde</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopiér gebyr</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopiér eftergebyr</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopiér byte</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopiér støv</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopiér byttepenge</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 fastlå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>Denne mærkat bliver rød, hvis en eller flere modtagere modtager et beløb, der er mindre end den aktuelle støvgrænse.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Kan variere med ±%1 satoshi per input.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ingen mærkat)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>byttepenge fra %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(byttepange)</translation>
</message>
</context>
<context>
@@ -486,6 +725,38 @@
<source>&amp;Address</source>
<translation>&amp;Adresse</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Ny modtagelsesadresse</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Ny afsendelsesadresse</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Redigér modtagelsesadresse</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Redigér afsendelsesadresse</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Den indtastede adresse “%1” er ikke en gyldig Bitcoin-adresse.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Den indtastede adresse “%1” er allerede i adressebogen.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Kunne ikke låse tegnebog op.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Ny nøglegenerering mislykkedes.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -546,7 +817,7 @@
</message>
<message>
<source>Set language, for example "de_DE" (default: system locale)</source>
- <translation>Vælg sprog; fx "da_DK" (standard: systemsprog)</translation>
+ <translation>Vælg sprog; fx “da_DK” (standard: systemsprog)</translation>
</message>
<message>
<source>Start minimized</source>
@@ -593,7 +864,7 @@
</message>
<message>
<source>Error: Specified data directory "%1" cannot be created.</source>
- <translation>Fejl: Angivet datamappe "%1" kan ikke oprettes.</translation>
+ <translation>Fejl: Angivet datamappe “%1” kan ikke oprettes.</translation>
</message>
<message>
<source>Error</source>
@@ -605,7 +876,58 @@
</message>
<message numerus="yes">
<source>(of %n GB needed)</source>
- <translation><numerusform>(ud af %n GB behøvet)</numerusform><numerusform>(ud af %n GB behøvet)</numerusform></translation>
+ <translation><numerusform>(ud af %n GB nødvendig)</numerusform><numerusform>(ud af %n GB nødvendig)</numerusform></translation>
+ </message>
+</context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <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>Nylige transaktioner er måske ikke synlige endnu, og derfor kan din tegnebogs saldo være ukorrekt. Denne information vil være korrekt, når din tegnebog er færdig med at synkronisere med bitcoin-netværket, som detaljerne herunder viser.</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>Forsøg på at bruge bitcoin, som er indeholdt i endnu-ikke-viste transaktioner, accepteres ikke af netværket.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Antal blokke tilbage</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Ukendt…</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Tidsstempel for seneste blok</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>Fremgang</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Øgning af fremgang pr. time</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>beregner…</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Estimeret tid tilbage af synkronisering</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Skjul</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Ukendt. Synkroniserer hoveder (%1)…</translation>
</message>
</context>
<context>
@@ -626,6 +948,10 @@
<source>Select payment request file</source>
<translation>Vælg fil for betalingsanmodning</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Vælg fil for betalingsanmodning til åbning</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -715,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>Hvis du slår brug af ubekræftede byttepenge fra, kan byttepengene fra en transaktion ikke bruges, før pågældende transaktion har mindst én bekræftelse. Dette påvirker også måden hvorpå din saldo beregnes.</translation>
+ <translation>Hvis du deaktiverer brug af ubekræftede byttepenge, kan byttepengene fra en transaktion ikke bruges, før pågældende transaktion har mindst én bekræftelse. Dette påvirker også måden hvorpå din saldo beregnes.</translation>
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
@@ -938,6 +1264,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Fejl i betalingsanmodning</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Kan ikke starte bitcoin: click-to-pay-håndtering</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>URI-håndtering</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>Hentnings-URL for betalingsanmodning er ugyldig: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Ugyldig betalingsadresse %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 ikke tolkes! Dette kan skyldes en ugyldig Bitcoin-adresse eller forkert udformede URL-parametre.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Filhåndtering for betalingsanmodninger</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>Fil for betalingsanmodning kan ikke læses! Dette kan skyldes en ugyldig fil for betalingsanmodning.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Betalingsanmodning afvist</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Netværk for betalingsanmodning stemmer ikke overens med klientens netværk.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Betalingsanmodning er udløbet.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Betalingsanmodning er ikke klargjort.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Ikke-verificerede betalingsanmodninger for tilpassede betalings-scripts understøttes ikke.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Ugyldig betalingsanmodning.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Anmodet betalingsbeløb på %1 er for lille (regnes som støv).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Tilbagebetaling fra %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>Betalingsanmodning %1 er for stor (%2 byte; %3 byte tilladt).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Fejl under kommunikation med %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Betalingsanmodning kan ikke tolkes!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Fejlagtigt svar fra server %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Fejl i netværksforespørgsel</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Betaling anerkendt</translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -948,8 +1365,12 @@
<translation>Knude/tjeneste</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Ping-tid</translation>
+ <source>NodeId</source>
+ <translation>Knude-id</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
</message>
</context>
<context>
@@ -990,6 +1411,72 @@
<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 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 dage</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n uge</numerusform><numerusform>%n uger</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>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 har endnu ikke afsluttet på sikker vis…</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Fejl: Angivet datamappe “%1” eksisterer ikke.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>Fejl: Kan ikke fortolke konfigurationsfil: %1. Brug kun syntaksen nøgle=værdi.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Fejl: %1</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>Gem billede…</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Kopiér foto</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Gem QR-kode</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG-billede (*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1150,6 +1637,10 @@
<translation>Ping-ventetid</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Minimum ping</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Tidsforskydning</translation>
</message>
@@ -1194,14 +1685,6 @@
<translation>Ryd konsol</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Afbryd forbindelse til knude</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Bandlys knude i</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;time</translation>
</message>
@@ -1218,8 +1701,16 @@
<translation>1 &amp;år</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Fjern bandlysning af knude</translation>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Afbryd forbindelse</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Bandlys i</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Fjern bandlysning</translation>
</message>
<message>
<source>Welcome to the %1 RPC console.</source>
@@ -1234,6 +1725,14 @@
<translation>Tast &lt;b&gt;help&lt;/b&gt; for en oversigt over de tilgængelige kommandoer.</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>ADVARSEL: Svindlere har tidligere forsøgt at få folk til at indtaste kommandoer her og derved stjæle indholdet af deres tegnebog. Brug ikke denne konsol uden fuldt ud at forstå følgerne for en kommando.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Netværksaktivitet deaktiveret</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1352,6 +1851,22 @@
<source>Remove</source>
<translation>Fjern</translation>
</message>
+ <message>
+ <source>Copy URI</source>
+ <translation>Kopiér URI</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiér mærkat</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Kopiér besked</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiér beløb</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1371,6 +1886,73 @@
<source>&amp;Save Image...</source>
<translation>&amp;Gem billede…</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Anmod om betaling til %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Betalingsinformation</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Beløb</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Mærkat</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Besked</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>Resulterende URI var for lang; prøv at forkorte teksten til mærkaten/beskeden.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Fejl ved kodning fra URI til QR-kode.</translation>
+ </message>
+</context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Dato</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Mærkat</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Besked</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ingen mærkat)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(ingen besked)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(intet anmodet beløb)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Anmodet</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1407,10 +1989,6 @@
<translation>Beløb:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritet:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Gebyr:</translation>
</message>
@@ -1448,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>Hvis det brugertilpassede gebyr er sat til 1000 satoshis, og transaktionen kun fylder 250 byte, betaler "pr. kilobyte" kun 250 satoshis i gebyr, mens "total mindst" betaler 1000 satoshis. For transaktioner større end en kilobyte betaler begge pr. kilobyte.</translation>
+ <translation>Hvis det brugertilpassede gebyr er sat til 1000 satoshis, og transaktionen kun fylder 250 byte, betaler “pr. kilobyte” kun 250 satoshis i gebyr, mens “total mindst” betaler 1000 satoshis. For transaktioner større end en kilobyte betaler begge pr. kilobyte.</translation>
</message>
<message>
<source>Hide</source>
@@ -1479,10 +2057,6 @@
<translation>(Smart-gebyr er ikke initialiseret endnu. Dette tager typisk nogle få blokke…)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Bekræftelsestid:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1507,6 +2081,10 @@
<translation>Støv:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Mål for bekræftelsestid:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Ryd &amp;alle</translation>
</message>
@@ -1522,6 +2100,126 @@
<source>S&amp;end</source>
<translation>&amp;Afsend</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopiér mængde</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiér beløb</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopiér gebyr</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopiér eftergebyr</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopiér byte</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopiér støv</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopiér byttepenge</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 til %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Er du sikker på, at du vil sende?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>tilføjet som transaktionsgebyr</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Beløb i alt %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>eller</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Bekræft afsendelse af bitcoins</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Modtageradressen er ikke gyldig. Tjek venligst igen.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Beløbet til betaling skal være større end 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Beløbet overstiger din saldo.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>Totalen overstiger din saldo, når transaktionsgebyret på %1 er inkluderet.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Adressegenganger fundet. Adresser bør kun bruges én gang hver.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Oprettelse af transaktion mislykkedes!</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>Transaktionen blev afvist med følgende begrundelse: %1</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Et gebyr højere end %1 opfattes som et absurd højt gebyr.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Betalingsanmodning er udløbet.</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n blok</numerusform><numerusform>%n blokke</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Betal kun det påkrævede gebyr på %1</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Bekræftelse estimeret til at begynde om %n blok.</numerusform><numerusform>Bekræftelse estimeret til at begynde om %n blokke.</numerusform></translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Advarsel: Ugyldig Bitcoin-adresse</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Advarsel: Ukendt byttepengeadresse</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>Bekræft tilpasset byttepengeadresse</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 adresse, du har valgt til byttepenge, er ikke en del af denne tegnebog. Nogle af eller alle penge i din tegnebog kan blive sendt til denne adresse. Er du sikker?</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ingen mærkat)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1591,7 +2289,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>En besked, som blev føjet til "bitcon:"-URI'en, som vil gemmes med transaktionen til din reference. Bemærk: Denne besked vil ikke blive sendt over Bitcoin-netværket.</translation>
+ <translation>En besked, som blev føjet til “bitcon:”-URI'en, som vil gemmes med transaktionen til din reference. Bemærk: Denne besked vil ikke blive sendt over Bitcoin-netværket.</translation>
</message>
<message>
<source>Pay To:</source>
@@ -1601,6 +2299,17 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Indtast en mærkat for denne adresse for at føje den til din adressebog</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1617,11 +2326,11 @@
<name>SignVerifyMessageDialog</name>
<message>
<source>Signatures - Sign / Verify a Message</source>
- <translation>Signature - Underskriv/verificér en besked</translation>
+ <translation>Signaturer – Underskriv/verificér en besked</translation>
</message>
<message>
<source>&amp;Sign Message</source>
- <translation>&amp;Underskriv besked</translation>
+ <translation>&amp;Singér besked</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>
@@ -1649,27 +2358,27 @@
</message>
<message>
<source>Enter the message you want to sign here</source>
- <translation>Indtast her beskeden, du ønsker at underskrive</translation>
+ <translation>Indtast her beskeden, du ønsker at signere</translation>
</message>
<message>
<source>Signature</source>
- <translation>Underskrift</translation>
+ <translation>Signatur</translation>
</message>
<message>
<source>Copy the current signature to the system clipboard</source>
- <translation>Kopiér den nuværende underskrift til systemets udklipsholder</translation>
+ <translation>Kopiér den nuværende signatur til systemets udklipsholder</translation>
</message>
<message>
<source>Sign the message to prove you own this Bitcoin address</source>
- <translation>Underskriv denne besked for at bevise, at Bitcoin-adressen tilhører dig</translation>
+ <translation>Signér denne besked for at bevise, at Bitcoin-adressen tilhører dig</translation>
</message>
<message>
<source>Sign &amp;Message</source>
- <translation>Underskriv &amp;besked</translation>
+ <translation>Signér &amp;besked</translation>
</message>
<message>
<source>Reset all sign message fields</source>
- <translation>Nulstil alle "underskriv besked"-felter</translation>
+ <translation>Nulstil alle “signér besked”-felter</translation>
</message>
<message>
<source>Clear &amp;All</source>
@@ -1689,7 +2398,7 @@
</message>
<message>
<source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
- <translation>Verificér beskeden for at sikre, at den er underskrevet med den angivne Bitcoin-adresse</translation>
+ <translation>Verificér beskeden for at sikre, at den er signeret med den angivne Bitcoin-adresse</translation>
</message>
<message>
<source>Verify &amp;Message</source>
@@ -1697,7 +2406,59 @@
</message>
<message>
<source>Reset all verify message fields</source>
- <translation>Nulstil alle "verificér besked"-felter</translation>
+ <translation>Nulstil alle “verificér besked”-felter</translation>
+ </message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Klik “Signér besked” for at generere underskriften</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>Den indtastede adresse er ugyldig.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Tjek venligst adressen og forsøg igen.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>Den indtastede adresse henviser ikke til en nøgle.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Tegnebogsoplåsning annulleret.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Den private nøgle for den indtastede adresse er ikke tilgængelig.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Signering af besked mislykkedes.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Besked signeret.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Signaturen kunne ikke afkodes.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Tjek venligst signaturen og forsøg igen.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>Signaturen passer ikke overens med beskedens indhold.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Verificering af besked mislykkedes.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Besked verificeret.</translation>
</message>
</context>
<context>
@@ -1715,11 +2476,460 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Åben i %n yderligere blok</numerusform><numerusform>Åben i %n yderligere blokke</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Åben indtil %1</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>i konflikt med en transaktion, der har %1 bekræftelser</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/offline</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/ubekræftet, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>i hukommelsespulje</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>ikke i hukommelsespulje</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>opgivet</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/ubekræftet</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 bekræftelser</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Status</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, er ikke blevet transmitteret endnu</translation>
+ </message>
+ <message numerus="yes">
+ <source>, broadcast through %n node(s)</source>
+ <translation><numerusform>, transmitteret igennem %n knude</numerusform><numerusform>, transmitteret igennem %n knuder</numerusform></translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Dato</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Kilde</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Genereret</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Fra</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>ukendt</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Til</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>egen adresse</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>kigge</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>mærkat</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Kredit</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>modner om %n blok</numerusform><numerusform>modner om %n blokke</numerusform></translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>ikke accepteret</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Debet</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Total debet</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Total kredit</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Transaktionsgebyr</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Nettobeløb</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Besked</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>Totalstørrelse af transaktion</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Outputindeks</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Forretningsdrivende</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>Minede bitcoins skal modne %1 blokke, før de kan bruges. Da du genererede denne blok, blev den transmitteret til netværket for at blive føjet til blokkæden. Hvis det ikke lykkes at få den i kæden, vil dens tilstand ændres til “ikke accepteret”, og den vil ikke kunne bruges. Dette kan ske nu og da, hvis en anden knude udvinder en blok inden for nogle få sekunder fra din.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Fejlsøgningsinformation</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transaktion</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Input</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Beløb</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>sand</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>Denne rude viser en detaljeret beskrivelse af transaktionen</translation>
</message>
+ <message>
+ <source>Details for %1</source>
+ <translation>Detaljer for %1</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Dato</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Type</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Mærkat</translation>
+ </message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Åben i %n yderligere blok</numerusform><numerusform>Åben i %n yderligere blokke</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Åben indtil %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Offline</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Ubekræftet</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Opgivet</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Bekræfter (%1 af %2 anbefalede bekræftelser)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Bekræftet (%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>Umoden (%1 bekræftelser; vil være tilgængelig efter %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Denne blok blev ikke modtaget af nogen andre knuder og vil formentlig ikke blive accepteret!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Genereret, men ikke accepteret</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Modtaget med</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Modtaget fra</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Sendt til</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Betaling til dig selv</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minet</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>kigge</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/a)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ingen mærkat)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Transaktionsstatus. Hold musen over dette felt for at vise antallet af bekræftelser.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Dato og klokkeslæt for modtagelse af transaktionen.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Transaktionstype.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Afgør hvorvidt en kigge-adresse er involveret i denne transaktion.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Brugerdefineret hensigt/formål med transaktionen.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Beløb trukket fra eller tilføjet balance.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Alle</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>I dag</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Denne uge</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Denne måned</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Sidste måned</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>I år</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Interval…</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Modtaget med</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Sendt til</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Til dig selv</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minet</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Andet</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Indtast adresse eller mærkat for at søge</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Minimumsbeløb</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Opgiv transaktion</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopiér adresse</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiér mærkat</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiér beløb</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopiér transaktions-ID</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Kopiér rå transaktion</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Kopiér komplette transaktionsdetaljer</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Redigér mærkat</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Vis transaktionsdetaljer</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Eksportér transaktionshistorik</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kommasepareret fil (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Bekræftet</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Kigge</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Dato</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Type</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Mærkat</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksport mislykkedes</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>En fejl opstod under gemning af transaktionshistorik til %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Eksport problemfri</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>Transaktionshistorikken blev gemt til %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Interval:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>til</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1729,6 +2939,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Ingen tegnebog er indlæst.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Send bitcoins</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Eksportér</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Eksportér den aktuelle visning til en fil</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Sikkerhedskopiér tegnebog</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Tegnebogsdata (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Sikkerhedskopiering mislykkedes</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Der skete en fejl under gemning af tegnebogsdata til %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Sikkerhedskopiering problemfri</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Tegnebogsdata blev gemt til %1.</translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1751,6 +3010,18 @@
<translation>Acceptér kommandolinje- og JSON-RPC-kommandoer</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>Acceptér forbindelser udefra (standard: 1 hvis 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>Forbind kun til de specificerede knuder; -noconnect eller -connect=0 alene for at deaktivere automatiske forbindelser</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>Distribueret under MIT-softwarelicensen; se den vedlagte fil %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>Hvis &lt;category&gt; ikke angives eller hvis &lt;category&gt; = 1, udskriv al fejlretningsinformation.</translation>
</message>
@@ -1763,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 = slå beskæring af blokke fra, &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>
@@ -1791,10 +3058,6 @@
<translation>Kunne ikke starte HTTP-server. Se fejlretningslog for detaljer.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Acceptér forbindelser udefra (standard: 1 hvis hverken -proxy eller -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1803,10 +3066,6 @@
<translation>Udviklerne af %s</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee er sat meget højt! Dette er transaktionsgebyret, du eventuelt betaler, hvis gebyrestimater ikke er tilgængelige.</translation>
- </message>
- <message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
<translation>En gebyrsats (i %s/kB), som vil blive brugt, hvis gebyrestimering har utilstrækkelig data (standard: %s)</translation>
</message>
@@ -1827,10 +3086,6 @@
<translation>Slet alle transaktioner i tegnebogen og genskab kun disse dele af blokkæden gennem -rescan under opstart</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribueret under MIT-softwarelicensen; se den vedlagte fil COPYING eller &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
<translation>Fejl under indlæsning af %s: Du kan ikke aktivere HD på en allerede eksisterende ikke-HD-tegnebog</translation>
</message>
@@ -1843,8 +3098,12 @@
<translation>Udfør kommando, når en transaktion i tegnebogen ændres (%s i kommandoen erstattes med TxID)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Gennemtving videresendelse af transaktioner fra hvidlistede knuder, selv om de overtræder lokal videresendelsespolitik (standard: %d)</translation>
+ <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>
@@ -1863,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>
@@ -1872,7 +3139,7 @@
</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>Dette er en foreløbig testudgivelse - brug på eget ansvar - brug ikke til udvinding eller handelsprogrammer</translation>
+ <translation>Dette er en foreløbig testudgivelse – brug på eget ansvar – brug ikke til mining eller handelsprogrammer</translation>
</message>
<message>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
@@ -1883,6 +3150,14 @@
<translation>Brug UPnP for at konfigurere den lyttende port (standard: 1 under lytning og ingen -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>Brugernavn og hashet adgangskode for JSON-RPC-forbindelser. Feltet &lt;userpw&gt; er i formatet: &lt;BRUGERNAVN&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Et kanonisk Python-skript er inkluderet i share/rpcuser. Klienten forbinder så normalt ved hjælp af argumentparret rpcuser=&lt;BRUGERNAVN&gt;/rpcpassword=&lt;ADGANGSKODE&gt;. Dette tilvalg kan angives flere gange</translation>
+ </message>
+ <message>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation>Tegnebogen vil ikke oprette transaktioner, som overtræder begrænsningen for hukommelsespuljekæden (standard: %u)</translation>
+ </message>
+ <message>
<source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
<translation>Advarsel: Netværket ser ikke ud til at være fuldt ud enige! Enkelte minere ser ud til at opleve problemer.</translation>
</message>
@@ -1891,10 +3166,6 @@
<translation>Advarsel: Vi ser ikke ud til at være fuldt ud enige med andre knuder! Du kan være nødt til at opgradere, eller andre knuder kan være nødt til at opgradere.</translation>
</message>
<message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Sæt andre knuder, der forbinder fra den angivne netmaske eller IP, på hvidliste. Kan angives flere gange.</translation>
- </message>
- <message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation>Du er nødt til at genopbygge databasen ved hjælp af -reindex-chainstate for at ændre -txindex</translation>
</message>
@@ -1924,15 +3195,15 @@
</message>
<message>
<source>Cannot resolve -%s address: '%s'</source>
- <translation>Kan ikke finde -%s-adressen: "%s"</translation>
+ <translation>Kan ikke finde -%s-adressen: “%s”</translation>
</message>
<message>
- <source>Change index out of range</source>
- <translation>Ændr indeks uden for interval</translation>
+ <source>Chain selection options:</source>
+ <translation>Indstillinger for kædevalg:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Tilslut kun til de(n) angivne knude(r)</translation>
+ <source>Change index out of range</source>
+ <translation>Ændr indeks uden for interval</translation>
</message>
<message>
<source>Connection options:</source>
@@ -1952,7 +3223,7 @@
</message>
<message>
<source>Do not load the wallet and disable wallet RPC calls</source>
- <translation>Indlæs ikke tegnebogen og slå tegnebogs-RPC-kald fra</translation>
+ <translation>Indlæs ikke tegnebogen og deaktivér tegnebogs-RPC-kald</translation>
</message>
<message>
<source>Do you want to rebuild the block database now?</source>
@@ -2032,15 +3303,15 @@
</message>
<message>
<source>Invalid -onion address: '%s'</source>
- <translation>Ugyldig -onion adresse: "%s"</translation>
+ <translation>Ugyldig -onion adresse: “%s”</translation>
</message>
<message>
<source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
- <translation>Ugyldigt beløb for -%s=&lt;beløb&gt;: "%s"</translation>
+ <translation>Ugyldigt beløb for -%s=&lt;beløb&gt;: “%s”</translation>
</message>
<message>
<source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
- <translation>Ugyldigt beløb for -fallbackfee=&lt;beløb&gt;: "%s"</translation>
+ <translation>Ugyldigt beløb for -fallbackfee=&lt;beløb&gt;: “%s”</translation>
</message>
<message>
<source>Keep the transaction memory pool below &lt;n&gt; megabytes (default: %u)</source>
@@ -2055,10 +3326,6 @@
<translation>Placering for autentificerings-cookie (standard: datamappe)</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>Minimum bytes pr. sigop i transaktioner, vi videresender og miner (standard: %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>For få tilgængelige fildeskriptorer.</translation>
</message>
@@ -2099,10 +3366,6 @@
<translation>Sæt cache-størrelse for database i megabytes (%d til %d; standard: %d)</translation>
</message>
<message>
- <source>Set maximum block cost (default: %d)</source>
- <translation>Sæt maksimal blokudgift (standard: %d)</translation>
- </message>
- <message>
<source>Set maximum block size in bytes (default: %d)</source>
<translation>Sæt maksimum blokstørrelse i byte (standard: %d)</translation>
</message>
@@ -2135,6 +3398,10 @@
<translation>Brug UPnP til at konfigurere den lyttende port (standard: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Brug testkæden</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>Brugeragent-kommentar (%s) indeholder usikre tegn.</translation>
</message>
@@ -2176,7 +3443,7 @@
</message>
<message>
<source>Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)</source>
- <translation>Opret nye filer med systemstandard for rettigheder i stedet for umask 077 (kun virksomt med tegnebogsfunktionalitet slået fra)</translation>
+ <translation>Opret nye filer med systemstandard for rettigheder i stedet for umask 077 (kun virksomt med tegnebogsfunktionalitet deaktiveret)</translation>
</message>
<message>
<source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source>
@@ -2200,17 +3467,13 @@
</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>Ugyldigt beløb for -maxtxfee=&lt;beløb&gt;: "%s" (skal være på mindst minrelay-gebyret på %s for at undgå hængende transaktioner)</translation>
+ <translation>Ugyldigt beløb for -maxtxfee=&lt;beløb&gt;: “%s” (skal være på mindst minrelay-gebyret på %s for at undgå hængende transaktioner)</translation>
</message>
<message>
<source>Maximum size of data in data carrier transactions we relay and mine (default: %u)</source>
<translation>Maksimal størrelse på data i transaktioner til dataoverførsel, som vi videresender og miner (standard: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Forespørgsel</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Brug tilfældige akkreditiver for hver proxy-forbindelse. Dette aktiverer strømisolation med Tor (standard: %u)</translation>
</message>
@@ -2223,10 +3486,6 @@
<translation>Transaktionsbeløbet er for lille til at sende, når gebyret er trukket fra</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Dette produkt indeholder software, der er udviklet af OpenSSL-projektet for brug i OpenSSL-værktøjskassen &lt;https://www.openssl.org/&gt;, samt kryptografisk software, der er skrevet af Eric Young, samt UPnP-software, der er skrevet af Thomas Bernard.</translation>
- </message>
- <message>
<source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
<translation>Brug hierarkisk deterministisk nøglegenerering (HD) efter BIP32. Har kun effekt ved generering af ny tegnebog og under første opstart</translation>
</message>
@@ -2268,11 +3527,11 @@
</message>
<message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
- <translation>Ugyldigt beløb for -paytxfee=&lt;beløb&gt;: "%s" (skal være mindst %s)</translation>
+ <translation>Ugyldigt beløb for -paytxfee=&lt;beløb&gt;: “%s” (skal være mindst %s)</translation>
</message>
<message>
<source>Invalid netmask specified in -whitelist: '%s'</source>
- <translation>Ugyldig netmaske angivet i -whitelist: "%s"</translation>
+ <translation>Ugyldig netmaske angivet i -whitelist: “%s”</translation>
</message>
<message>
<source>Keep at most &lt;n&gt; unconnectable transactions in memory (default: %u)</source>
@@ -2280,7 +3539,7 @@
</message>
<message>
<source>Need to specify a port with -whitebind: '%s'</source>
- <translation>Nødt til at angive en port med -whitebinde: "%s"</translation>
+ <translation>Nødt til at angive en port med -whitebinde: “%s”</translation>
</message>
<message>
<source>Node relay options:</source>
@@ -2316,7 +3575,7 @@
</message>
<message>
<source>Signing transaction failed</source>
- <translation>Underskrift af transaktion mislykkedes</translation>
+ <translation>Signering af transaktion mislykkedes</translation>
</message>
<message>
<source>The transaction amount is too small to pay the fee</source>
@@ -2339,10 +3598,6 @@
<translation>Transaktionsbeløb er for lavt</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Transaktionsbeløb skal være positive</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transaktion for stor til gebyrretningslinjer</translation>
</message>
@@ -2407,18 +3662,22 @@
<translation>-maxtxfee er sat meget højt! Gebyrer så store risikeres betalt på en enkelt transaktion.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee er sat meget højt! Dette er transaktionsgebyret, som du betaler, hvis du sender en transaktion.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Behold ikke transaktioner i hukommelsespuljen i mere end &lt;n&gt; timer (default: %u)</translation>
</message>
<message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Tilsvarende bytes pr. sigop i transaktioner, som videresendes og mines (standard: %u)</translation>
+ </message>
+ <message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation>Gebyrer (i %s/kB) mindre end dette opfattes som intet gebyr under oprettelse af transaktioner (standard: %s)</translation>
</message>
<message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>Gennemtving videresendelse af transaktioner fra hvidlistede knuder, selv om de overtræder lokal videresendelsespolitik (standard: %d)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>Hvor gennemarbejdet blokverificeringen for -checkblocks er (0-4; standard: %u)</translation>
</message>
@@ -2435,10 +3694,26 @@
<translation>Udskriv fejlsøgningsinformation (standard: %u, angivelse af &lt;kategori&gt; er valgfri)</translation>
</message>
<message>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
+ <translation>Forespørg knudeadresser via DNS-opslag hvis antallet af adresser er lavt (standard: 1 med mindre -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>Indstiller serialiseringen af rå transaktioner eller blok-hex returneret i ikke-verbose tilstand, non-segwit(0) eller sigwit(1) (standard: %d)</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation>Understøt filtrering af blokke og transaktioner med Bloom-filtre (standard: %u)</translation>
</message>
<message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Dette er transaktionsgebyret, du kan betale, når gebyrestimeringer ikke er tilgængelige.</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>Dette produkt indeholder software, der er udviklet af OpenSSL-projektet for brug i OpenSSL-værktøjskassen %s, samt kryptografisk software, der er skrevet af Eric Young, samt UPnP-software, der er skrevet af 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>Den totale længde på netværksversionsstrengen (%i) overstiger maksimallængden (%i). Reducér antaller af eller størrelsen på uacomments.</translation>
</message>
@@ -2459,10 +3734,6 @@
<translation>Brug separat SOCS5-proxy for at nå knuder via skjulte Tor-tjenester (standard: %s)</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. This option can be specified multiple times</source>
- <translation>Brugernavn og hashet adgangskode for JSON-RPC-forbindelser. Feltet &lt;userpw&gt; er i formatet: &lt;BRUGERNAVN&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Et kanonisk Python-skript inkluderes i share/rpcuser. Dette tilvalg kan angives flere gange</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>Advarsel: Ukendte blokversioner bliver minet! Det er muligt, at ukendte regler er i brug</translation>
</message>
@@ -2471,6 +3742,14 @@
<translation>Advarsel: Tegnebogsfil ødelagt, data reddet! Oprindelig %s gemt som %s i %s; hvis din saldo eller dine transaktioner er forkert, bør du genskabe fra en sikkerhedskopi.</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>Sæt knuder på hvidliste, som forbinder fra den givne IP-adresse (fx 1.2.3.4) eller CIDR-noteret netværk (fx 1.2.3.0/24). Kan angives flere gange.</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation>%s er meget højt sat!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(standard: %s)</translation>
</message>
@@ -2488,7 +3767,11 @@
</message>
<message>
<source>Invalid -proxy address: '%s'</source>
- <translation>Ugyldig -proxy adresse: "%s"</translation>
+ <translation>Ugyldig -proxy adresse: “%s”</translation>
+ </message>
+ <message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Nøglepulje løb tør; kald venligst keypoolrefill først</translation>
</message>
<message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
@@ -2527,13 +3810,17 @@
<translation>Videresend ikke-P2SH multisig (standard: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>Send transaktioner med fuld-RBF opt-in aktiveret (standard: %u)</translation>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation>Sæt nøglepuljestørrelse til &lt;n&gt; (standard: %u)
</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Angiv minimumsblokstørrelse i byte (standard: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Sæt maksimal BIP141-blokvægt (standard: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
@@ -2556,12 +3843,40 @@
<translation>Brug ubekræftede byttepenge under afsendelse af transaktioner (standard: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Starter netværkstråde…</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>Tegnebogen vil undgå at betale mindre end minimum-videresendelsesgebyret.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Dette er det transaktionsgebyr, du minimum betaler for hver transaktion.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Dette er transaktionsgebyret, som betaler, når du sender en transaktion.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Grænse for afbrydelse af forbindelse til knuder, der opfører sig upassende (standard: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Transaktionsbeløb må ikke være negative</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>Transaktionen har en for lang hukommelsespuljekæde</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>Transaktionen skal have mindst én modtager</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
- <translation>Ukendt netværk anført i -onlynet: "%s"</translation>
+ <translation>Ukendt netværk anført i -onlynet: “%s”</translation>
</message>
<message>
<source>Insufficient funds</source>
diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts
index 2708324d17..af79d47736 100644
--- a/src/qt/locale/bitcoin_de.ts
+++ b/src/qt/locale/bitcoin_de.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Löschen</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Wählen Sie die Adresse aus, an die Sie Bitcoins überweisen möchten</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Wählen Sie die Adresse aus, über die Sie Bitcoins empfangen wollen</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Auswählen</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Zahlungsadressen</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Empfangsadressen</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>Dies sind ihre Bitcoin-Adressen zum Tätigen von Überweisungen. Bitte prüfen Sie den Betrag und die Empfangsadresse, bevor Sie Bitcoins überweisen.</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>Dies sind Ihre Bitcoin-Adressen zum Empfangen von Zahlungen. Es wird empfohlen, für jede Transaktion eine neue Empfangsadresse zu verwenden.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>Adresse &amp;kopieren</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>&amp;Bezeichnung kopieren</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Editieren</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Addressliste exportieren</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kommagetrennte-Datei (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Exportieren fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Beim Speichern der Adressliste nach %1 ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Bezeichnung</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(keine Bezeichnung)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>Neue Passphrase bestätigen</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>Geben Sie die neue Passphrase für die Wallet ein.&lt;br&gt;Bitte benutzen Sie eine Passphrase bestehend aus &lt;b&gt;zehn oder mehr zufälligen Zeichen&lt;/b&gt; oder &lt;b&gt;acht oder mehr Wörtern&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Wallet verschlüsseln</translation>
+ </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>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Wallet entsperren</translation>
+ </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>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Wallet entschlüsseln</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Passphrase ändern</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Geben Sie die alte und neue Wallet-Passphrase ein.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Wallet-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>
+ </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>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Wallet 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>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>WICHTIG: Alle vorherigen Wallet-Sicherungen sollten durch die neu erzeugte, verschlüsselte Wallet ersetzt werden. Aus Sicherheitsgründen werden vorherige Sicherungen der unverschlüsselten Wallet nutzlos, sobald Sie die neue, verschlüsselte Wallet verwenden.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Wallet-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>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Die eingegebenen Passphrasen stimmen nicht überein.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Wallet-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>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Wallet-Entschlüsselung fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Die Wallet-Passphrase wurde erfolgreich geändert.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Warnung: Die Feststelltaste ist aktiviert!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -112,7 +271,7 @@
</message>
<message>
<source>&amp;About %1</source>
- <translation>&amp;Über %1</translation>
+ <translation>Über %1</translation>
</message>
<message>
<source>Show information about %1</source>
@@ -159,6 +318,22 @@
<translation>&amp;URI öffnen...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Klicken zum Deaktivieren der Netzwerkaktivität.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Netzwerkaktivität deaktiviert.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <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>
@@ -270,34 +445,10 @@
<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>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n Stunde</numerusform><numerusform>%n Stunden</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n Tag</numerusform><numerusform>%n Tage</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n Woche</numerusform><numerusform>%n Wochen</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 und %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n Jahr</numerusform><numerusform>%n Jahre</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 im Rückstand</translation>
@@ -335,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>
@@ -377,6 +532,14 @@
<translation>Eingehende Transaktion</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>HD Schlüssel Generierung ist &lt;b&gt;aktiviert&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>HD Schlüssel Generierung ist &lt;b&gt;deaktiviert&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>Wallet ist &lt;b&gt;verschlüsselt&lt;/b&gt; und aktuell &lt;b&gt;entsperrt&lt;/b&gt;</translation>
</message>
@@ -384,6 +547,10 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Wallet ist &lt;b&gt;verschlüsselt&lt;/b&gt; und aktuell &lt;b&gt;gesperrt&lt;/b&gt;</translation>
</message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Ein schwerer Fehler ist aufgetreten. Bitcoin kann nicht stabil weiter ausgeführt werden und wird beendet.</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -404,10 +571,6 @@
<translation>Betrag:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorität:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Gebühr:</translation>
</message>
@@ -460,8 +623,84 @@
<translation>Bestätigt</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Priorität</translation>
+ <source>Copy address</source>
+ <translation>Adresse kopieren</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Bezeichnung kopieren</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Betrag kopieren</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Transaktionskennung kopieren</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Nicht ausgegebenen Betrag sperren</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Nicht ausgegebenen Betrag entsperren</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Anzahl kopieren</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Gebühr kopieren</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Abzüglich Gebühr kopieren</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Byte kopieren</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>"Staub" kopieren</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Wechselgeld kopieren</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 gesperrt)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>ja</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>nein</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Diese Bezeichnung wird rot, wenn irgendein Empfänger einen Betrag kleiner als die derzeitige "Staubgrenze" erhält.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Kann pro Eingabe um +/- %1 Satoshi(s) abweichen.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(keine Bezeichnung)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>Wechselgeld von %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(Wechselgeld)</translation>
</message>
</context>
<context>
@@ -486,6 +725,38 @@
<source>&amp;Address</source>
<translation>&amp;Adresse</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Neue Empfangsadresse</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Neue Zahlungsadresse</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Empfangsadresse bearbeiten</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Zahlungsadresse bearbeiten</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Die eingegebene Adresse "%1" ist keine gültige Bitcoin-Adresse.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Die eingegebene Adresse "%1" befindet sich bereits im Adressbuch.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Wallet konnte nicht entsperrt werden.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Erzeugung eines neuen Schlüssels fehlgeschlagen.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -609,6 +880,49 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formular</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Anzahl verbleibender Blöcke</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Unbekannt...</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Letzte Blockzeit</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>Fortschritt</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Fortschritt pro Stunde</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>berechne...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Abschätzung der verbleibenden Zeit bis synchronisiert</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Ausblenden</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Unbekannt. Synchronisiere Headers (%1)...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -626,6 +940,10 @@
<source>Select payment request file</source>
<translation>Zahlungsanforderungsdatei auswählen</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Zu öffnende Zahlungsanforderungsdatei auswählen</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -810,6 +1128,10 @@
<translation>&amp;Sprache der Benutzeroberfläche:</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>Die Benutzeroberflächensprache kann hier festgelegt werden. Diese Einstellung wird nach einem Neustart von %1 wirksam werden.</translation>
+ </message>
+ <message>
<source>&amp;Unit to show amounts in:</source>
<translation>&amp;Einheit der Beträge:</translation>
</message>
@@ -934,6 +1256,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>fehlerhafte Zahlungsanforderung</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Kann Bitcoin nicht starten: Klicken-zum-Bezahlen-Handler</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>URI-Verarbeitung</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>Abruf-URL der Zahlungsanforderung ist ungültig: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Ungültige Zahlungsadresse %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 kann nicht analysiert werden! Dies kann durch eine ungültige Bitcoin-Adresse oder fehlerhafte URI-Parameter verursacht werden.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Zahlungsanforderungsdatei-Verarbeitung</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>Zahlungsanforderungsdatei kann nicht gelesen werden! Dies kann durch eine ungültige Zahlungsanforderungsdatei verursacht werden.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Zahlungsanforderung abgelehnt</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Netzwerk der Zahlungsanforderung stimmt nicht mit dem Client-Netzwerk überein.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Zahlungsanforderung abgelaufen.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Zahlungsanforderung ist nicht initialisiert.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Unverifizierte Zahlungsanforderungen an benutzerdefinierte Zahlungsskripte werden nicht unterstützt.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Ungültige Zahlungsanforderung.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Angeforderter Zahlungsbetrag in Höhe von %1 ist zu niedrig und wurde als "Staub" eingestuft.</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Rücküberweisung von %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>Zahlungsanforderung %1 ist zu groß (%2 Byte, erlaubt sind %3 Byte).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Kommunikationsfehler mit %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Zahlungsanforderung kann nicht verarbeitet werden!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Fehlerhafte Antwort vom Server: %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>fehlerhafte Netzwerkanfrage</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Zahlung bestätigt</translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -944,8 +1357,12 @@
<translation>Knoten/Dienst</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Pingzeit</translation>
+ <source>NodeId</source>
+ <translation>Knoten Identität</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
</message>
</context>
<context>
@@ -986,6 +1403,68 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n Sekunde</numerusform><numerusform>%n Sekunde(n)</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n Minute</numerusform><numerusform>%n Minute(n)</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n Stunde</numerusform><numerusform>%n Stunden</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n Tag</numerusform><numerusform>%n Tage</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n Woche</numerusform><numerusform>%n Wochen</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 und %2</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 wurde noch nicht sicher beendet...</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Fehler: Angegebenes Datenverzeichnis "%1" existiert nicht.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>Fehler: Konfigurationsdatei kann nicht analysiert werden: %1. Bitte nur "Schlüssel=Wert"-Syntax verwenden.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Fehler: %1</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>Grafik &amp;speichern...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>Grafik &amp;kopieren</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>QR-Code speichern</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG-Grafik (*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1146,6 +1625,10 @@
<translation>Ping Wartezeit</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Minimaler Ping</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Zeitversatz</translation>
</message>
@@ -1190,14 +1673,6 @@
<translation>Konsole zurücksetzen</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>Knoten &amp;trennen</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Knoten gebannt für</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;Stunde</translation>
</message>
@@ -1214,7 +1689,15 @@
<translation>1 &amp;Jahr</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Trennen</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Banne für</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
<translation>&amp;Node entsperren</translation>
</message>
<message>
@@ -1230,6 +1713,14 @@
<translation>Bitte &lt;b&gt;help&lt;/b&gt; eingeben, um eine Übersicht verfügbarer Befehle zu erhalten.</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>WARNUNG: Betrüger versuchen aktiv Nutzer dazu zu bringen Kommandos hier auszuführen um die Wallet Inhalte zu stehlen. Diese Konsole sollte nicht benutzt werden ausser man kennt die möglichen Folgen des Kommandos.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Netzwerkaktivität deaktiviert</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1348,6 +1839,22 @@
<source>Remove</source>
<translation>Entfernen</translation>
</message>
+ <message>
+ <source>Copy URI</source>
+ <translation>&amp;URI kopieren</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Bezeichnung kopieren</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Nachricht kopieren</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Betrag kopieren</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1367,6 +1874,73 @@
<source>&amp;Save Image...</source>
<translation>Grafik &amp;speichern...</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Zahlung anfordern an %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Zahlungsinformationen</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Betrag</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Bezeichnung</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Nachricht</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>Resultierende URI ist zu lang, bitte den Text für Bezeichnung/Nachricht kürzen.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Beim Enkodieren der URI in den QR-Code ist ein Fehler aufgetreten.</translation>
+ </message>
+</context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Bezeichnung</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Nachricht</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(keine Bezeichnung)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(keine Nachricht)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(kein Betrag angefordert)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Angefordert</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1403,10 +1977,6 @@
<translation>Betrag:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorität:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Gebühr:</translation>
</message>
@@ -1475,10 +2045,6 @@
<translation>(Intelligente Gebührenlogik ist noch nicht verfügbar. Normalerweise dauert dies einige Blöcke lang...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Bestätigungszeit:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1503,6 +2069,10 @@
<translation>"Dust":</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Gewünschte Bestätigungszeit:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>&amp;Zurücksetzen</translation>
</message>
@@ -1518,6 +2088,122 @@
<source>S&amp;end</source>
<translation>&amp;Überweisen</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Anzahl kopieren</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Betrag kopieren</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Gebühr kopieren</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Abzüglich Gebühr kopieren</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Byte kopieren</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>"Staub" kopieren</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Wechselgeld kopieren</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 an %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Wollen Sie die Überweisung ausführen?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>als Transaktionsgebühr hinzugefügt</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Gesamtbetrag %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>oder</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Überweisung bestätigen</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Die Zahlungsadresse ist ungültig, bitte nochmals überprüfen.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Der zu zahlende Betrag muss größer als 0 sein.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Der angegebene Betrag übersteigt Ihren Kontostand.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>Der angegebene Betrag übersteigt aufgrund der Transaktionsgebühr in Höhe von %1 Ihren Kontostand.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Doppelte Adresse entdeckt: Adressen dürfen jeweils nur einmal vorkommen.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Transaktionserstellung fehlgeschlagen!</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>Die Transaktion wurde aus folgendem Grund abgelehnt: %1</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Eine höhere Gebühr als %1 wird als unsinnig hohe Gebühr angesehen.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Zahlungsanforderung abgelaufen.</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n Block</numerusform><numerusform>%n Blöcke</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Nur die notwendige Gebühr in Höhe von %1 zahlen</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Voraussichtlicher Beginn der Bestätigung innerhalb von %n Block.</numerusform><numerusform>Voraussichtlicher Beginn der Bestätigung innerhalb von %n Blöcken.</numerusform></translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Warnung: Ungültige Bitcoin-Adresse</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Warnung: Unbekannte Wechselgeld-Adresse</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>Bestätige benutzerdefinierte Wechselgeld-Adresse</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(keine Bezeichnung)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1597,6 +2283,17 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Geben Sie eine Bezeichnung für diese Adresse ein, um sie zu Ihrem Adressbuch hinzuzufügen</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1695,6 +2392,58 @@
<source>Reset all verify message fields</source>
<translation>Alle "Nachricht verifizieren"-Felder zurücksetzen</translation>
</message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Auf "Nachricht signieren" klicken, um die Signatur zu erzeugen</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>Die eingegebene Adresse ist ungültig.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Bitte überprüfen Sie die Adresse und versuchen Sie es erneut.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>Die eingegebene Adresse verweist nicht auf einen Schlüssel.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Wallet-Entsperrung wurde abgebrochen.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Privater Schlüssel zur eingegebenen Adresse ist nicht verfügbar.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Signierung der Nachricht fehlgeschlagen.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Nachricht signiert.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Die Signatur konnte nicht dekodiert werden.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Bitte überprüfen Sie die Signatur und versuchen Sie es erneut.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>Die Signatur entspricht nicht dem "Message Digest".</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Verifikation der Nachricht fehlgeschlagen.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Nachricht verifiziert.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1711,11 +2460,460 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Offen für %n weiteren Block</numerusform><numerusform>Offen für %n weitere Blöcke</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Offen bis %1</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>steht im Konflikt mit einer Transaktion mit %1 Bestätigungen</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/offline</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>%1/unbestätigt</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>im Speicherpool</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>nicht im Speicherpool</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>eingestellt</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/unbestätigt</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 Bestätigungen</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Status</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, wurde noch nicht erfolgreich übertragen</translation>
+ </message>
+ <message numerus="yes">
+ <source>, broadcast through %n node(s)</source>
+ <translation><numerusform>, über %n Knoten übertragen</numerusform><numerusform>, über %n Knoten übertragen</numerusform></translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Quelle</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Erzeugt</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Von</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>unbekannt</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>An</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>eigene Adresse</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>beobachtet</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>Bezeichnung</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Gutschrift</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>reift noch %n weiteren Block</numerusform><numerusform>reift noch %n weitere Blöcke</numerusform></translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>nicht angenommen</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Belastung</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Gesamtbelastung</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Gesamtgutschrift</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Transaktionsgebühr</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Nettobetrag</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Nachricht</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Kommentar</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>Transaktionskennung</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation>Gesamte Transaktionsgröße</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Ausgabeindex</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Händler</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>Erzeugte Bitcoins müssen %1 Blöcke lang reifen, bevor sie ausgegeben werden können. Als Sie diesen Block erzeugten, wurde er an das Netzwerk übertragen, um ihn der Blockkette hinzuzufügen. Falls dies fehlschlägt wird der Status in "nicht angenommen" geändert und Sie werden keine Bitcoins gutgeschrieben bekommen. Das kann gelegentlich passieren, wenn ein anderer Knoten einen Block fast zeitgleich erzeugt.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Debuginformationen</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transaktion</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Eingaben</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Betrag</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>wahr</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>falsch</translation>
+ </message>
+</context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Dieser Bereich zeigt eine detaillierte Beschreibung der Transaktion an</translation>
</message>
+ <message>
+ <source>Details for %1</source>
+ <translation>Details 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>Bezeichnung</translation>
+ </message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Offen für %n weiteren Block</numerusform><numerusform>Offen für %n weitere Blöcke</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Offen bis %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Offline</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Unbestätigt</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Eingestellt</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Wird bestätigt (%1 von %2 empfohlenen Bestätigungen)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Bestätigt (%1 Bestätigungen)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>in Konflikt stehend</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Unreif (%1 Bestätigungen, wird verfügbar sein nach %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Dieser Block wurde vom Netzwerk nicht angenommen und wird wahrscheinlich nicht bestätigt werden!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Generiert, aber nicht akzeptiert</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Empfangen über</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Empfangen von</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Überwiesen an</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Eigenüberweisung</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Erarbeitet</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>beobachtet</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(k.A.)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(keine Bezeichnung)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Transaktionsstatus. Fahren Sie mit der Maus über dieses Feld, um die Anzahl der Bestätigungen zu sehen.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Datum und Zeit als die Transaktion empfangen wurde.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Art der Transaktion</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Zeigt an, ob eine beobachtete Adresse in diese Transaktion involviert ist.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Benutzerdefinierte Absicht bzw. Verwendungszweck der Transaktion</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Der Betrag, der dem Kontostand abgezogen oder hinzugefügt wurde.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Alle</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Heute</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Diese Woche</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Diesen Monat</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Letzten Monat</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Dieses Jahr</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Zeitraum...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Empfangen über</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Überwiesen an</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Eigenüberweisung</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Erarbeitet</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Andere</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Zu suchende Adresse oder Bezeichnung eingeben</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Mindestbetrag</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Transaktion einstellen</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Adresse kopieren</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Bezeichnung kopieren</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Betrag kopieren</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Transaktionskennung kopieren</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Rohe Transaktion kopieren</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Vollständige Transaktionsdetails kopieren</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Bezeichnung bearbeiten</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Transaktionsdetails anzeigen</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Transaktionsverlauf exportieren</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kommagetrennte-Datei (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Bestätigt</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Nur beobachten</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Typ</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Bezeichnung</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Exportieren fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Beim Speichern des Transaktionsverlaufs nach %1 ist ein Fehler aufgetreten.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Exportieren erfolgreich</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>Speichern des Transaktionsverlaufs nach %1 war erfolgreich.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Zeitraum:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>bis</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1725,6 +2923,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Es wurde keine Wallet geladen.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Bitcoins überweisen</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>E&amp;xportieren</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Daten der aktuellen Ansicht in eine Datei exportieren</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Wallet sichern</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Wallet-Daten (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Sicherung fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Beim Speichern der Wallet-Daten nach %1 ist ein Fehler aufgetreten.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Sicherung erfolgreich</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Speichern der Wallet-Daten nach %1 war erfolgreich.</translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1747,6 +2994,14 @@
<translation>Kommandozeilen- und JSON-RPC-Befehle annehmen</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>Eingehende Verbindungen annehmen (Standard: 1, wenn nicht -proxy oder -connect/-noconnect)</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>
+ <message>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation>Wenn &lt;category&gt; nicht angegeben wird oder &lt;category&gt;=1, jegliche Debugginginformationen ausgeben.</translation>
</message>
@@ -1755,8 +3010,12 @@
<translation>Kürzungsmodus wurde kleiner als das Minimum in Höhe von %d MiB konfiguriert. Bitte verwenden Sie einen größeren Wert.</translation>
</message>
<message>
- <source>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>
+ <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>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>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>
<message>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
@@ -1779,22 +3038,22 @@
<translation>Kann HTTP Server nicht starten. Siehe debug log für Details.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Eingehende Verbindungen annehmen (Standard: 1, wenn nicht -proxy oder -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee ist sehr hoch eingestellt! Das ist die Transaktionsgebühr, welche du zahlen müsstest, wenn die Gebührenschätzungen nicht verfügbar sind.</translation>
+ <source>The %s developers</source>
+ <translation>Die %s-Entwickler</translation>
</message>
<message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
<translation>Eine Transaktionsgebühr (in %s/kB) wird genutzt, wenn für die Gebührenschützung zu wenig Daten vorliegen (Standardwert: %s)</translation>
</message>
<message>
+ <source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
+ <translation>Geben Sie immer die Transaktionen, die Sie von freigegebenen Peers erhalten haben, weiter (Voreinstellung: %d)</translation>
+ </message>
+ <message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
<translation>An die angegebene Adresse binden und immer abhören. Für IPv6 "[Host]:Port"-Notation verwenden</translation>
</message>
@@ -1807,16 +3066,20 @@
<translation>Alle Wallet-Transaktionen löschen und nur diese Teilbereiche der Blockkette durch -rescan beim Starten wiederherstellen</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Veröffentlicht unter der MIT-Softwarelizenz, siehe beiligende Datei COPYING oder &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
+ <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>
<message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Befehl ausführen wenn sich eine Wallet-Transaktion verändert (%s im Befehl wird durch die Transaktions-ID ersetzt)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Leite Transaktionen von Peers auf der Positivliste auf jeden Fall weiter, auch wenn sie die lokale Weiterleitungsregeln verletzen (Standardeinstellung: %d)</translation>
+ <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>
+ </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>Maximale Gesamtgebühr (in %s) in einer Börsentransaktion; wird dies zu niedrig gesetzten können große Transaktionen abgebrochen werden (Standard: %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>
@@ -1839,10 +3102,18 @@
<translation>Dies ist eine Vorab-Testversion - Verwendung auf eigene Gefahr - nicht für Mining- oder Handelsanwendungen nutzen!</translation>
</message>
<message>
+ <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
+ <translation>Sie müssen die Datenbank mit Hilfe von -reindex neu aufbauen, um zum ungekürzten Modus zurückzukehren. Dies erfordert, dass die gesamte Blockkette erneut heruntergeladen wird.</translation>
+ </message>
+ <message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<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>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>
@@ -1851,10 +3122,6 @@
<translation>Warnung: Wir scheinen nicht vollständig mit unseren Gegenstellen übereinzustimmen! Sie oder die anderen Knoten müssen unter Umständen Ihre Client-Software aktualisieren.</translation>
</message>
<message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Gegenstellen die sich von der angegebenen Netzmaske oder IP-Adresse aus verbinden immer zulassen. Kann mehrmals angegeben werden.</translation>
- </message>
- <message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation>Sie müssen die Datenbank mit Hilfe von -reindex-chainstate neu aufbauen, um -txindex zu verändern</translation>
</message>
@@ -1887,8 +3154,8 @@
<translation>Kann Adresse in -%s nicht auflösen: '%s'</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Mit nur dem oder den angegebenen Knoten verbinden</translation>
+ <source>Change index out of range</source>
+ <translation>Position des Wechselgelds außerhalb des Bereichs</translation>
</message>
<message>
<source>Connection options:</source>
@@ -1931,6 +3198,10 @@
<translation>Aktiviere das Veröffentlichen der Roh-Transaktion in &lt;address&gt;</translation>
</message>
<message>
+ <source>Enable transaction replacement in the memory pool (default: %u)</source>
+ <translation>Maximal &lt;n&gt; nicht-verbindbare Transaktionen im Speicher halten (Standard: %u)</translation>
+ </message>
+ <message>
<source>Error initializing block database</source>
<translation>Fehler beim Initialisieren der Blockdatenbank</translation>
</message>
@@ -1975,6 +3246,10 @@
<translation>Fehlerhafter oder kein Genesis-Block gefunden. Falsches Datenverzeichnis für das Netzwerk?</translation>
</message>
<message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation>Initialisierungsplausibilitätsprüfung fehlgeschlagen. %s wird beendet.</translation>
+ </message>
+ <message>
<source>Invalid -onion address: '%s'</source>
<translation>Ungültige "-onion"-Adresse: '%s'</translation>
</message>
@@ -2023,6 +3298,18 @@
<translation>Kürzungsmodus ist nicht mit -txindex kompatibel.</translation>
</message>
<message>
+ <source>Rebuild chain state and block index from the blk*.dat files on disk</source>
+ <translation>Blockkettenindex aus aktuellen Dateien blk000??.dat beim Starten wiederaufbauen</translation>
+ </message>
+ <message>
+ <source>Rebuild chain state from the currently indexed blocks</source>
+ <translation>Blockkettenindex aus aktuellen Dateien blk000??.dat wiederaufbauen</translation>
+ </message>
+ <message>
+ <source>Rewinding blocks...</source>
+ <translation>Verifiziere Blöcke...</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>Größe des Datenbankcaches in Megabyte festlegen (%d bis %d, Standard: %d)</translation>
</message>
@@ -2059,6 +3346,10 @@
<translation>UPnP verwenden, um eine Portweiterleitung einzurichten (Standard: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Die Testchain verwenden</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>Der User Agent Kommentar (%s) enthält unsichere Zeichen.</translation>
</message>
@@ -2075,6 +3366,14 @@
<translation>Wallet %s liegt außerhalb des Datenverzeichnisses %s</translation>
</message>
<message>
+ <source>Wallet debugging/testing options:</source>
+ <translation>Wallet Debugging-/Testoptionen:</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>Wallet musste neu geschrieben werden: starten Sie %s zur Fertigstellung neu</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Wallet-Optionen:</translation>
</message>
@@ -2123,10 +3422,6 @@
<translation>Maximale Datengröße in "Data Carrier"-Transaktionen die weitergeleitet und erarbeitet werden (Standard: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Adressen von Gegenstellen via DNS-Namensauflösung finden, falls zu wenige Adressen verfügbar sind (Standard: 1, außer bei -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Zufällige Anmeldedaten für jede Proxyverbindung verwenden. Dies aktiviert Tor-Datenflussisolation (Standard: %u)</translation>
</message>
@@ -2139,8 +3434,8 @@
<translation>Der Transaktionsbetrag ist zum senden zu niedrig, nachdem die Gebühr abgezogen wurde.</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im OpenSSL-Toolkit &lt;https://www.openssl.org/&gt; entwickelt wird, sowie von Eric Young geschriebene kryptographische Software und von Thomas Bernard geschriebene UPnP-Software.</translation>
+ <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>
</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>
@@ -2251,10 +3546,6 @@
<translation>Transaktionsbetrag zu niedrig</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Transaktionsbeträge müssen positiv sein</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transaktion ist für die Gebührenrichtlinie zu groß</translation>
</message>
@@ -2319,18 +3610,22 @@
<translation>-maxtxfee ist auf einen sehr hohen Wert festgelegt! Gebühren dieser Höhe könnten für eine einzelne Transaktion bezahlt werden.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee ist auf einen sehr hohen Wert festgelegt! Dies ist die Gebühr die beim Senden einer Transaktion fällig wird.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Die Transaktion nicht länger im Speicherpool behalten als &lt;n&gt; Stunden (Standard: %u)</translation>
</message>
<message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Maximale Datengröße in "Data Carrier"-Transaktionen die weitergeleitet und erarbeitet werden (Standard: %u)</translation>
+ </message>
+ <message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation>Niedrigere Gebühren (in %s/Kb) als diese werden bei der Transaktionserstellung als gebührenfrei angesehen (Standard: %s)</translation>
</message>
<message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>Leite Transaktionen von Peers auf der Positivliste auf jeden Fall weiter, auch wenn sie die lokale Weiterleitungsregeln verletzen (Standardeinstellung: %d)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>Legt fest, wie gründlich die Blockverifikation von -checkblocks ist (0-4, Standard: %u)</translation>
</message>
@@ -2347,6 +3642,18 @@
<translation>Debugginginformationen ausgeben (Standard: %u, &lt;category&gt; anzugeben ist optional)</translation>
</message>
<message>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
+ <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>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>
+ <message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Das ist die Transaktionsgebühr, welche du zahlen müsstest, wenn die Gebührenschätzungen nicht verfügbar sind.</translation>
+ </message>
+ <message>
<source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
<translation>Gesamtlänge des Netzwerkversionstrings (%i) erreicht die maximale Länge (%i). Reduzieren Sie die Nummer oder die Größe von uacomments.</translation>
</message>
@@ -2367,14 +3674,18 @@
<translation>Separaten SOCKS5-Proxy verwenden, um Gegenstellen über versteckte Tor-Dienste zu erreichen (Standard: %s)</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. 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. Diese Option kann mehrere Male spezifiziert werden</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>Warnung: Unbekannte Blockversion wird durch Mining erzeugt! Es ist möglich, dass unbekannte Regeln in Kraft sind.</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>Gegenstellen die sich von der angegebenen IP-Adresse (e.g. 1.2.3.4) oder CIDR Notation (eg. 1.2.3.0/24) aus verbinden immer zulassen. Kann mehrmals angegeben werden.</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation>%s wurde sehr hoch Eingestellt!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(Standard: %s)</translation>
</message>
@@ -2431,12 +3742,16 @@
<translation>Nicht-"P2SH-Multisig" weiterleiten (Standard: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>Wähle alle zu sendenden Transaktionen als full-RBF (Standard: %u)</translation>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation>Größe des Schlüsselpools festlegen auf &lt;n&gt; (Standard: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Minimale Blockgröße in Byte festlegen (Standard: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Maximales BIP141 Blockgewicht festlegen (Standard: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
@@ -2459,10 +3774,22 @@
<translation>Unbestätigtes Wechselgeld darf beim Senden von Transaktionen ausgegeben werden (Standard: %u)</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>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Dies ist die Gebühr die beim Senden einer Transaktion fällig wird.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Schwellenwert, um Verbindungen zu sich nicht konform verhaltenden Gegenstellen zu beenden (Standard: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Transaktionsbeträge dürfen nicht negativ sein.</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.ts b/src/qt/locale/bitcoin_el.ts
index de76a110cf..61e5a1cec8 100644
--- a/src/qt/locale/bitcoin_el.ts
+++ b/src/qt/locale/bitcoin_el.ts
@@ -7,6 +7,9 @@
</message>
</context>
<context>
+ <name>AddressTableModel</name>
+ </context>
+<context>
<name>AskPassphraseDialog</name>
<message>
<source>Enter passphrase</source>
@@ -20,7 +23,7 @@
<source>Repeat new passphrase</source>
<translation>Επαναλάβετε νέο συνθηματικό</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -56,7 +59,7 @@
<source>&amp;Address</source>
<translation>Διεύθυνση</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -79,6 +82,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -92,12 +98,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>Services</source>
@@ -110,11 +125,14 @@
<source>Remove</source>
<translation>Αφαίρεση</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Insufficient funds!</source>
@@ -133,6 +151,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -145,12 +166,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Insufficient funds</source>
diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts
index 2814e4f6e7..0390a378e7 100644
--- a/src/qt/locale/bitcoin_el_GR.ts
+++ b/src/qt/locale/bitcoin_el_GR.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Διαγραφή</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Επανέλαβε τον νέο κωδικό πρόσβασης</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -243,14 +246,6 @@
<translation>&amp;Επιλογές γραμμής εντολών</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Η πηγή του μπλοκ δεν ειναι διαθέσιμη... </translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 και %2</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 πίσω</translation>
</message>
@@ -328,7 +323,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -348,10 +343,6 @@
<translation>Ποσό:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Προτεραιότητα:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Ταρίφα</translation>
</message>
@@ -403,11 +394,7 @@
<source>Confirmed</source>
<translation>Επικυρωμένες</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Προτεραιότητα</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -430,7 +417,7 @@
<source>&amp;Address</source>
<translation>&amp;Διεύθυνση</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -509,6 +496,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Φόρμα</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Χρόνος τελευταίου μπλοκ</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Απόκρυψη</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -526,7 +528,7 @@
<source>Select payment request file</source>
<translation>Επιλέξτε πληρωμή αρχείου αίτησης</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -787,12 +789,11 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
- <message>
- <source>Ping Time</source>
- <translation>Χρόνος καθυστέρησης</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -831,7 +832,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 και %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -1053,7 +1064,7 @@
<source>Remove</source>
<translation>Αφαίρεση</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1072,7 +1083,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Αποθήκευση εικόνας...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1108,10 +1122,6 @@
<translation>Ποσό:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Προτεραιότητα:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Ταρίφα</translation>
</message>
@@ -1160,10 +1170,6 @@
<translation>Προσαρμογή:</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Χρόνος επικύρωσης:</translation>
- </message>
- <message>
<source>normal</source>
<translation>κανονικό</translation>
</message>
@@ -1203,7 +1209,7 @@
<source>S&amp;end</source>
<translation>Αποστολη</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1262,7 +1268,10 @@
<source>Memo:</source>
<translation>Σημείωση:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1348,7 +1357,7 @@
<source>Reset all verify message fields</source>
<translation>Επαναφορά όλων επαλήθευμενων πεδίων μήνυματος </translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1364,12 +1373,21 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Αυτό το παράθυρο δείχνει μια λεπτομερή περιγραφή της συναλλαγής</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1378,6 +1396,15 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1404,10 +1431,6 @@
<translation>Εκτέλεση στο παρασκήνιο κι αποδοχή εντολών</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Να δέχεσαι συνδέσεις από έξω(προεπιλογή:1)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1420,18 +1443,10 @@
<translation>Εκτέλεσε την εντολή όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ)</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>Block creation options:</source>
<translation>Αποκλεισμός επιλογων δημιουργίας: </translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Σύνδεση μόνο με ορισμένους κόμβους</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Επιλογές σύνδεσης:</translation>
</message>
@@ -1552,10 +1567,6 @@
<translation>Το ποσό της συναλλαγής είναι πολύ μικρο </translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Τα ποσά των συναλλαγών πρέπει να είναι θετικα</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>Η συναλλαγή ειναι πολύ μεγάλη </translation>
</message>
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 79c3e87b2b..f62f1e4a73 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -53,6 +53,94 @@
<source>&amp;Delete</source>
<translation>&amp;Delete</translation>
</message>
+ <message>
+ <location filename="../addressbookpage.cpp" line="+50"/>
+ <source>Choose the address to send coins to</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Choose the address to receive coins with</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>C&amp;hoose</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Sending addresses</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Receiving addresses</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>&amp;Copy Address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy &amp;Label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>&amp;Edit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+193"/>
+ <source>Export Address List</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Comma separated file (*.csv)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+13"/>
+ <source>Exporting Failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <location filename="../addresstablemodel.cpp" line="+170"/>
+ <source>Label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+36"/>
+ <source>(no label)</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -76,11 +164,129 @@
<source>Repeat new passphrase</source>
<translation>Repeat new passphrase</translation>
</message>
+ <message>
+ <location filename="../askpassphrasedialog.cpp" line="+46"/>
+ <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 type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Encrypt wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Unlock wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Decrypt wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Change passphrase</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+44"/>
+ <source>Confirm wallet encryption</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <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 type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <location line="+58"/>
+ <source>Wallet encrypted</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-56"/>
+ <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 type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <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 type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <location line="+7"/>
+ <location line="+42"/>
+ <location line="+6"/>
+ <source>Wallet encryption failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-54"/>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <location line="+48"/>
+ <source>The supplied passphrases do not match.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-37"/>
+ <source>Wallet unlock failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <location line="+11"/>
+ <location line="+19"/>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-20"/>
+ <source>Wallet decryption failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+14"/>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+47"/>
+ <location line="+24"/>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
<message>
- <location filename="../bantablemodel.cpp" line="+88"/>
+ <location filename="../bantablemodel.cpp" line="+89"/>
<source>IP/Netmask</source>
<translation type="unfinished"></translation>
</message>
@@ -93,27 +299,27 @@
<context>
<name>BitcoinGUI</name>
<message>
- <location filename="../bitcoingui.cpp" line="+341"/>
+ <location filename="../bitcoingui.cpp" line="+357"/>
<source>Sign &amp;message...</source>
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+377"/>
+ <location line="+427"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-455"/>
+ <location line="-505"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
<message>
- <location line="-130"/>
+ <location line="-143"/>
<source>Node</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+131"/>
+ <location line="+144"/>
<source>Show general overview of wallet</source>
<translation>Show general overview of wallet</translation>
</message>
@@ -198,12 +404,32 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+372"/>
+ <location line="+357"/>
+ <source>Click to disable network activity.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Network activity disabled.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Click to enable network activity again.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <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="-457"/>
+ <location line="-508"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -233,17 +459,17 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
- <location line="+481"/>
+ <location line="+514"/>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
<message>
- <location line="-693"/>
+ <location line="-739"/>
<source>Wallet</source>
<translation>Wallet</translation>
</message>
<message>
- <location line="+139"/>
+ <location line="+152"/>
<source>&amp;Send</source>
<translation>&amp;Send</translation>
</message>
@@ -323,7 +549,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+341"/>
+ <location line="+354"/>
<source>%n active connection(s) to Bitcoin network</source>
<translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
@@ -331,7 +557,7 @@
</translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+60"/>
<source>Indexing blocks on disk...</source>
<translation type="unfinished"></translation>
</message>
@@ -340,64 +566,21 @@
<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>
<numerusform>Processed %n blocks of transaction history.</numerusform>
</translation>
</message>
- <message numerus="yes">
- <location line="+26"/>
- <source>%n hour(s)</source>
- <translation>
- <numerusform>%n hour</numerusform>
- <numerusform>%n hours</numerusform>
- </translation>
- </message>
- <message numerus="yes">
- <location line="+4"/>
- <source>%n day(s)</source>
- <translation>
- <numerusform>%n day</numerusform>
- <numerusform>%n days</numerusform>
- </translation>
- </message>
- <message numerus="yes">
- <location line="+4"/>
- <location line="+6"/>
- <source>%n week(s)</source>
- <translation>
- <numerusform>%n week</numerusform>
- <numerusform>%n weeks</numerusform>
- </translation>
- </message>
- <message>
- <location line="+0"/>
- <source>%1 and %2</source>
- <translation type="unfinished"></translation>
- </message>
- <message numerus="yes">
- <location line="+0"/>
- <source>%n year(s)</source>
- <translation type="unfinished">
- <numerusform>%n year</numerusform>
- <numerusform>%n years</numerusform>
- </translation>
- </message>
<message>
- <location line="+4"/>
+ <location line="+24"/>
<source>%1 behind</source>
<translation>%1 behind</translation>
</message>
<message>
- <location line="+21"/>
+ <location line="+24"/>
<source>Last received block was generated %1 ago.</source>
<translation>Last received block was generated %1 ago.</translation>
</message>
@@ -422,27 +605,32 @@
<translation>Information</translation>
</message>
<message>
- <location line="-95"/>
+ <location line="-78"/>
<source>Up to date</source>
<translation>Up to date</translation>
</message>
<message>
- <location line="-388"/>
+ <location line="-438"/>
<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="+188"/>
+ <location line="+197"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+244"/>
+ <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>
<message>
- <location line="+137"/>
+ <location line="+145"/>
<source>Date: %1
</source>
<translation type="unfinished"></translation>
@@ -482,7 +670,17 @@
<translation>Incoming transaction</translation>
</message>
<message>
- <location line="+62"/>
+ <location line="+52"/>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+19"/>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</translation>
</message>
@@ -491,6 +689,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<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"/>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -515,22 +718,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+29"/>
- <source>Priority:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+45"/>
+ <location line="+80"/>
<source>Fee:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+32"/>
+ <location line="-48"/>
<source>Dust:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+48"/>
+ <location line="+93"/>
<source>After Fee:</source>
<translation type="unfinished"></translation>
</message>
@@ -585,8 +783,105 @@
<translation type="unfinished">Confirmed</translation>
</message>
<message>
- <location line="+5"/>
- <source>Priority</source>
+ <location filename="../coincontroldialog.cpp" line="+55"/>
+ <source>Copy address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <location line="+26"/>
+ <source>Copy amount</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-25"/>
+ <source>Copy transaction ID</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Lock unspent</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Unlock unspent</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+22"/>
+ <source>Copy quantity</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Copy fee</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy after fee</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy bytes</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy dust</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy change</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+325"/>
+ <source>(%1 locked)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+183"/>
+ <source>yes</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>no</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+14"/>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+42"/>
+ <location line="+52"/>
+ <source>(no label)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-7"/>
+ <source>change from %1 (%2)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>(change)</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -617,6 +912,46 @@
<source>&amp;Address</source>
<translation>&amp;Address</translation>
</message>
+ <message>
+ <location filename="../editaddressdialog.cpp" line="+28"/>
+ <source>New receiving address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>New sending address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Edit receiving address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Edit sending address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+71"/>
+ <source>The entered address &quot;%1&quot; is not a valid Bitcoin address.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>The entered address &quot;%1&quot; is already in the address book.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Could not unlock wallet.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>New key generation failed.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -748,33 +1083,99 @@
<translation>Use a custom data directory:</translation>
</message>
<message>
- <location filename="../intro.cpp" line="+89"/>
+ <location filename="../intro.cpp" line="+94"/>
<source>Error: Specified data directory &quot;%1&quot; cannot be created.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+24"/>
+ <location line="+26"/>
<source>Error</source>
<translation>Error</translation>
</message>
<message numerus="yes">
<location line="+9"/>
<source>%n GB of free space available</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>%n GB of free space available</numerusform>
+ <numerusform>%n GB of free space available</numerusform>
</translation>
</message>
<message numerus="yes">
<location line="+3"/>
<source>(of %n GB needed)</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
</translation>
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <location filename="../forms/modaloverlay.ui" line="+14"/>
+ <source>Form</source>
+ <translation type="unfinished">Form</translation>
+ </message>
+ <message>
+ <location line="+119"/>
+ <source>Recent transactions may not yet be visible, and therefore your wallet&apos;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 type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+19"/>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+63"/>
+ <source>Number of blocks left</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <location line="+26"/>
+ <location filename="../modaloverlay.cpp" line="+138"/>
+ <source>Unknown...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-13"/>
+ <source>Last block time</source>
+ <translation type="unfinished">Last block time</translation>
+ </message>
+ <message>
+ <location line="+26"/>
+ <source>Progress</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+34"/>
+ <source>Progress increase per hour</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <location line="+20"/>
+ <source>calculating...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-7"/>
+ <source>Estimated time left until synced</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+37"/>
+ <source>Hide</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../modaloverlay.cpp" line="-1"/>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<location filename="../forms/openuridialog.ui" line="+14"/>
@@ -796,6 +1197,11 @@
<source>Select payment request file</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <location filename="../openuridialog.cpp" line="+47"/>
+ <source>Select payment request file to open</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -1106,7 +1512,7 @@
<translation>Form</translation>
</message>
<message>
- <location line="+59"/>
+ <location line="+62"/>
<location line="+386"/>
<source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
<translation>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</translation>
@@ -1193,6 +1599,132 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <location filename="../paymentserver.cpp" line="+328"/>
+ <location line="+216"/>
+ <location line="+42"/>
+ <location line="+113"/>
+ <location line="+14"/>
+ <location line="+18"/>
+ <source>Payment request error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-402"/>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+103"/>
+ <location line="+14"/>
+ <location line="+7"/>
+ <source>URI handling</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-20"/>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+13"/>
+ <source>Invalid payment address %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+13"/>
+ <source>Payment request file handling</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+61"/>
+ <location line="+9"/>
+ <location line="+31"/>
+ <location line="+10"/>
+ <location line="+17"/>
+ <location line="+88"/>
+ <source>Payment request rejected</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-155"/>
+ <source>Payment request network doesn&apos;t match client network.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>Payment request expired.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Payment request is not initialized.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+26"/>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <location line="+17"/>
+ <source>Invalid payment request.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-10"/>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+55"/>
+ <source>Refund from %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+44"/>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>Error communicating with %1: %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+20"/>
+ <source>Payment request cannot be parsed!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+13"/>
+ <source>Bad response from server %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+22"/>
+ <source>Network request error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+11"/>
+ <source>Payment acknowledged</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<location filename="../peertablemodel.cpp" line="+117"/>
@@ -1206,7 +1738,12 @@
</message>
<message>
<location line="+0"/>
- <source>Ping Time</source>
+ <source>NodeId</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Ping</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -1218,12 +1755,12 @@
<translation type="unfinished">Amount</translation>
</message>
<message>
- <location filename="../guiutil.cpp" line="+135"/>
+ <location filename="../guiutil.cpp" line="+136"/>
<source>Enter a Bitcoin address (e.g. %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+764"/>
+ <location line="+759"/>
<source>%1 d</source>
<translation type="unfinished"></translation>
</message>
@@ -1239,7 +1776,7 @@
</message>
<message>
<location line="+2"/>
- <location line="+47"/>
+ <location line="+50"/>
<source>%1 s</source>
<translation type="unfinished"></translation>
</message>
@@ -1258,6 +1795,106 @@
<source>%1 ms</source>
<translation type="unfinished"></translation>
</message>
+ <message numerus="yes">
+ <location line="+18"/>
+ <source>%n second(s)</source>
+ <translation>
+ <numerusform>%n second</numerusform>
+ <numerusform>%n seconds</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <location line="+4"/>
+ <source>%n minute(s)</source>
+ <translation>
+ <numerusform>%n minute</numerusform>
+ <numerusform>%n minutes</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <location line="+4"/>
+ <source>%n hour(s)</source>
+ <translation type="unfinished">
+ <numerusform>%n hour</numerusform>
+ <numerusform>%n hours</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <location line="+4"/>
+ <source>%n day(s)</source>
+ <translation type="unfinished">
+ <numerusform>%n day</numerusform>
+ <numerusform>%n days</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <location line="+4"/>
+ <location line="+6"/>
+ <source>%n week(s)</source>
+ <translation type="unfinished">
+ <numerusform>%n week</numerusform>
+ <numerusform>%n weeks</numerusform>
+ </translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>%1 and %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message numerus="yes">
+ <location line="+0"/>
+ <source>%n year(s)</source>
+ <translation type="unfinished">
+ <numerusform>%n year</numerusform>
+ <numerusform>%n years</numerusform>
+ </translation>
+ </message>
+ <message>
+ <location filename="../bitcoin.cpp" line="+172"/>
+ <source>%1 didn&apos;t yet exit safely...</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <message>
+ <location line="-81"/>
+ <source>Error: Specified data directory &quot;%1&quot; does not exist.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+14"/>
+ <source>Error: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <location filename="../receiverequestdialog.cpp" line="+36"/>
+ <source>&amp;Save Image...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>&amp;Copy Image</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+32"/>
+ <source>Save QR Code</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>PNG Image (*.png)</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1290,11 +1927,12 @@
<location line="+23"/>
<location line="+26"/>
<location line="+23"/>
+ <location line="+23"/>
<source>N/A</source>
<translation>N/A</translation>
</message>
<message>
- <location line="-1322"/>
+ <location line="-1345"/>
<source>Client version</source>
<translation>Client version</translation>
</message>
@@ -1392,8 +2030,8 @@
</message>
<message>
<location line="+60"/>
- <location filename="../rpcconsole.cpp" line="+295"/>
- <location line="+634"/>
+ <location filename="../rpcconsole.cpp" line="+456"/>
+ <location line="+719"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
</message>
@@ -1490,11 +2128,16 @@
</message>
<message>
<location line="+23"/>
+ <source>Min Ping</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+23"/>
<source>Time Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1093"/>
+ <location line="-1116"/>
<source>Last block time</source>
<translation>Last block time</translation>
</message>
@@ -1524,7 +2167,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-342"/>
+ <location filename="../rpcconsole.cpp" line="-413"/>
<source>In:</source>
<translation type="unfinished"></translation>
</message>
@@ -1544,45 +2187,45 @@
<translation>Clear console</translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-203"/>
- <source>&amp;Disconnect Node</source>
+ <location filename="../rpcconsole.cpp" line="-214"/>
+ <source>1 &amp;hour</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
- <location line="+1"/>
- <location line="+1"/>
- <location line="+1"/>
- <source>Ban Node for</source>
+ <source>1 &amp;day</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-3"/>
- <source>1 &amp;hour</source>
+ <location line="+1"/>
+ <source>1 &amp;week</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
- <source>1 &amp;day</source>
+ <source>1 &amp;year</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>1 &amp;week</source>
+ <location line="-4"/>
+ <source>&amp;Disconnect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
- <source>1 &amp;year</source>
+ <location line="+1"/>
+ <location line="+1"/>
+ <location line="+1"/>
+ <source>Ban for</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+46"/>
- <source>&amp;Unban Node</source>
+ <location line="+48"/>
+ <source>&amp;Unban</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+117"/>
+ <location line="+126"/>
<source>Welcome to the %1 RPC console.</source>
<translation type="unfinished"></translation>
</message>
@@ -1597,7 +2240,17 @@
<translation>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</translation>
</message>
<message>
- <location line="+146"/>
+ <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>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+36"/>
+ <source>Network activity disabled</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+150"/>
<source>%1 B</source>
<translation type="unfinished"></translation>
</message>
@@ -1617,7 +2270,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+88"/>
+ <location line="+99"/>
<source>(node id: %1)</source>
<translation type="unfinished"></translation>
</message>
@@ -1633,7 +2286,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+10"/>
<source>Inbound</source>
<translation type="unfinished"></translation>
</message>
@@ -1749,6 +2402,26 @@
<source>Remove</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <location filename="../receivecoinsdialog.cpp" line="+47"/>
+ <source>Copy URI</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy message</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy amount</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1772,11 +2445,95 @@
<source>&amp;Save Image...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <location filename="../receiverequestdialog.cpp" line="+65"/>
+ <source>Request payment to %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Payment information</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>URI</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Amount</source>
+ <translation type="unfinished">Amount</translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Message</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Error encoding URI into QR Code.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <location filename="../recentrequeststablemodel.cpp" line="+29"/>
+ <source>Date</source>
+ <translation type="unfinished">Date</translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Message</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+40"/>
+ <source>(no label)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>(no message)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>(no amount requested)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+42"/>
+ <source>Requested</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
+ <location filename="../sendcoinsdialog.cpp" line="+554"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -1816,17 +2573,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+32"/>
- <source>Priority:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+48"/>
+ <location line="+80"/>
<source>Fee:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+80"/>
+ <location line="+51"/>
<source>After Fee:</source>
<translation type="unfinished"></translation>
</message>
@@ -1908,17 +2660,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+29"/>
- <source>Confirmation time:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+60"/>
+ <location line="+89"/>
<source>normal</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+20"/>
+ <location line="+40"/>
<source>fast</source>
<translation type="unfinished"></translation>
</message>
@@ -1938,12 +2685,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-805"/>
+ <location line="-876"/>
<source>Dust:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+808"/>
+ <location line="+691"/>
+ <source>Confirmation time target:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+188"/>
<source>Clear &amp;All</source>
<translation>Clear &amp;All</translation>
</message>
@@ -1962,6 +2714,165 @@
<source>S&amp;end</source>
<translation>S&amp;end</translation>
</message>
+ <message>
+ <location filename="../sendcoinsdialog.cpp" line="-486"/>
+ <source>Copy quantity</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy amount</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy fee</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy after fee</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy bytes</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy dust</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy change</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+205"/>
+ <location line="+5"/>
+ <location line="+5"/>
+ <location line="+4"/>
+ <source>%1 to %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Are you sure you want to send?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>added as transaction fee</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+15"/>
+ <source>Total Amount %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>or</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Confirm send coins</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+191"/>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>The amount exceeds your balance.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Transaction creation failed!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <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"/>
+ <source>Pay only the required fee of %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message numerus="yes">
+ <location line="+25"/>
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation>
+ <numerusform>Estimated to begin confirmation within %n block.</numerusform>
+ <numerusform>Estimated to begin confirmation within %n blocks.</numerusform>
+ </translation>
+ </message>
+ <message>
+ <location line="+102"/>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>Warning: Unknown change address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Confirm custom change address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <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 type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+21"/>
+ <source>(no label)</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -2066,6 +2977,20 @@
<source>Memo:</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <location filename="../sendcoinsentry.cpp" line="+37"/>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <location filename="../sendcoinsdialog.cpp" line="+95"/>
+ <location line="+5"/>
+ <source>Yes</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -2190,6 +3115,77 @@
<source>Reset all verify message fields</source>
<translation>Reset all verify message fields</translation>
</message>
+ <message>
+ <location filename="../signverifymessagedialog.cpp" line="+41"/>
+ <source>Click &quot;Sign Message&quot; to generate signature</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+83"/>
+ <location line="+80"/>
+ <source>The entered address is invalid.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-80"/>
+ <location line="+8"/>
+ <location line="+72"/>
+ <location line="+8"/>
+ <source>Please check the address and try again.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-80"/>
+ <location line="+80"/>
+ <source>The entered address does not refer to a key.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-72"/>
+ <source>Wallet unlock was cancelled.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>Private key for the entered address is not available.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+12"/>
+ <source>Message signing failed.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Message signed.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+58"/>
+ <source>The signature could not be decoded.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <location line="+13"/>
+ <source>Please check the signature and try again.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>The signature did not match the message digest.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>Message verification failed.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Message verified.</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -2208,40 +3204,685 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <location filename="../transactiondesc.cpp" line="+30"/>
+ <source>Open for %n more block(s)</source>
+ <translation>
+ <numerusform>Open for %n more block</numerusform>
+ <numerusform>Open for %n more blocks</numerusform>
+ </translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Open until %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>%1/offline</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>0/unconfirmed, %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>in memory pool</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>not in memory pool</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>abandoned</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>%1/unconfirmed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>%1 confirmations</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+17"/>
+ <source>Status</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>, has not been successfully broadcast yet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message numerus="yes">
+ <location line="+2"/>
+ <source>, broadcast through %n node(s)</source>
+ <translation>
+ <numerusform>, broadcast through %n node</numerusform>
+ <numerusform>, broadcast through %n nodes</numerusform>
+ </translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Date</source>
+ <translation type="unfinished">Date</translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>Source</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Generated</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <location line="+13"/>
+ <location line="+72"/>
+ <source>From</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-72"/>
+ <source>unknown</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <location line="+20"/>
+ <location line="+69"/>
+ <source>To</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-87"/>
+ <source>own address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <location line="+69"/>
+ <source>watch-only</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <source>label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+34"/>
+ <location line="+12"/>
+ <location line="+53"/>
+ <location line="+26"/>
+ <location line="+55"/>
+ <source>Credit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message numerus="yes">
+ <location line="-144"/>
+ <source>matures in %n more block(s)</source>
+ <translation>
+ <numerusform>matures in %n more block</numerusform>
+ <numerusform>matures in %n more blocks</numerusform>
+ </translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>not accepted</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+59"/>
+ <location line="+25"/>
+ <location line="+55"/>
+ <source>Debit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-70"/>
+ <source>Total debit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Total credit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Transaction fee</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+16"/>
+ <source>Net amount</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <location line="+11"/>
+ <source>Message</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-9"/>
+ <source>Comment</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Transaction ID</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Transaction total size</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Output index</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+18"/>
+ <source>Merchant</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <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 &quot;not accepted&quot; and it won&apos;t be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>Debug information</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>Transaction</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Inputs</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+21"/>
+ <source>Amount</source>
+ <translation type="unfinished">Amount</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <location line="+1"/>
+ <source>true</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-1"/>
+ <location line="+1"/>
+ <source>false</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>TransactionDescDialog</name>
<message>
<location filename="../forms/transactiondescdialog.ui" line="+20"/>
<source>This pane shows a detailed description of the transaction</source>
<translation>This pane shows a detailed description of the transaction</translation>
</message>
+ <message>
+ <location filename="../transactiondescdialog.cpp" line="+17"/>
+ <source>Details for %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <location filename="../transactiontablemodel.cpp" line="+246"/>
+ <source>Date</source>
+ <translation type="unfinished">Date</translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Type</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message numerus="yes">
+ <location line="+58"/>
+ <source>Open for %n more block(s)</source>
+ <translation>
+ <numerusform>Open for %n more block</numerusform>
+ <numerusform>Open for %n more blocks</numerusform>
+ </translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Open until %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Offline</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Unconfirmed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Abandoned</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Conflicted</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Generated but not accepted</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+39"/>
+ <source>Received with</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Received from</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Sent to</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Payment to yourself</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Mined</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+28"/>
+ <source>watch-only</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+15"/>
+ <source>(n/a)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+213"/>
+ <source>(no label)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+39"/>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Date and time that the transaction was received.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Type of transaction.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Amount removed from or added to balance.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <location filename="../transactionview.cpp" line="+69"/>
+ <location line="+16"/>
+ <source>All</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-15"/>
+ <source>Today</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>This week</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>This month</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Last month</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>This year</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Range...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+11"/>
+ <source>Received with</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Sent to</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>To yourself</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Mined</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Other</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Enter address or label to search</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Min amount</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+36"/>
+ <source>Abandon transaction</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy amount</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy transaction ID</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy raw transaction</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Copy full transaction details</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Edit label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Show transaction details</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+186"/>
+ <source>Export Transaction History</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Comma separated file (*.csv)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>Confirmed</source>
+ <translation type="unfinished">Confirmed</translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Watch-only</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Date</source>
+ <translation type="unfinished">Date</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Type</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Label</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>ID</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Exporting Failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Exporting Successful</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+147"/>
+ <source>Range:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>to</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
- <location filename="../bitcoingui.cpp" line="+116"/>
+ <location filename="../bitcoingui.cpp" line="+129"/>
<source>Unit to show amounts in. Click to select another unit.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <location filename="../walletframe.cpp" line="+27"/>
+ <source>No wallet has been loaded.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <location filename="../walletmodel.cpp" line="+291"/>
+ <source>Send Coins</source>
+ <translation type="unfinished">Send Coins</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <location filename="../walletview.cpp" line="+46"/>
+ <source>&amp;Export</source>
+ <translation type="unfinished">&amp;Export</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Export the data in the current tab to a file</source>
+ <translation type="unfinished">Export the data in the current tab to a file</translation>
+ </message>
+ <message>
+ <location line="+201"/>
+ <source>Backup Wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Wallet Data (*.dat)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Backup Failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Backup Successful</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
- <location filename="../bitcoinstrings.cpp" line="+292"/>
+ <location filename="../bitcoinstrings.cpp" line="+318"/>
<source>Options:</source>
<translation>Options:</translation>
</message>
<message>
- <location line="+30"/>
+ <location line="+31"/>
<source>Specify data directory</source>
<translation>Specify data directory</translation>
</message>
<message>
- <location line="-89"/>
+ <location line="-90"/>
<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="+92"/>
+ <location line="+93"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
@@ -2251,12 +3892,27 @@
<translation>Accept command line and JSON-RPC commands</translation>
</message>
<message>
- <location line="-128"/>
+ <location line="-221"/>
+ <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"/>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+37"/>
<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>
@@ -2266,17 +3922,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
- <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 type="unfinished"></translation>
- </message>
- <message>
- <location line="+5"/>
+ <location line="+18"/>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+119"/>
+ <location line="+132"/>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
<translation type="unfinished"></translation>
</message>
@@ -2296,17 +3947,12 @@
<translation>Run in the background as a daemon and accept commands</translation>
</message>
<message>
- <location line="+30"/>
+ <location line="+37"/>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-121"/>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation>
- </message>
- <message>
- <location line="-206"/>
+ <location line="-360"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
@@ -2316,17 +3962,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+9"/>
+ <location line="+7"/>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+6"/>
<source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -2341,17 +3982,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+8"/>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+5"/>
+ <location line="+13"/>
<source>Error loading %s: You can&apos;t enable HD on a already existing non-HD wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -2366,12 +4002,17 @@
<translation>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</translation>
</message>
<message>
- <location line="+12"/>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
+ <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="+17"/>
+ <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>
@@ -2391,22 +4032,32 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+24"/>
- <source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
+ <location line="+14"/>
+ <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>
+ <message>
+ <location line="+12"/>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
+ <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>
+ <message>
+ <location line="+8"/>
<source>The block database contains a block which appears to be from the future. This may be due to your computer&apos;s date and time being set incorrectly. Only rebuild the block database if you are sure that your computer&apos;s date and time are correct</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
- <translation>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation>
+ <translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
+ <location line="+15"/>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
<translation type="unfinished"></translation>
</message>
@@ -2416,22 +4067,27 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+12"/>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</translation>
+ <location line="+8"/>
+ <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 type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
- <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>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</translation>
+ <location line="+6"/>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+10"/>
+ <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 type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+12"/>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation type="unfinished"></translation>
</message>
@@ -2441,7 +4097,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>-maxmempool must be at least %d MB</source>
<translation type="unfinished"></translation>
</message>
@@ -2451,7 +4107,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+6"/>
<source>Append comment to the user agent string</source>
<translation type="unfinished"></translation>
</message>
@@ -2472,13 +4128,13 @@
</message>
<message>
<location line="+2"/>
- <source>Change index out of range</source>
+ <source>Chain selection options:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
- <source>Connect only to the specified node(s)</source>
- <translation>Connect only to the specified node(s)</translation>
+ <source>Change index out of range</source>
+ <translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
@@ -2621,7 +4277,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+5"/>
<source>Loading banlist...</source>
<translation type="unfinished"></translation>
</message>
@@ -2631,12 +4287,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+7"/>
<source>Not enough file descriptors available.</source>
<translation>Not enough file descriptors available.</translation>
</message>
@@ -2681,7 +4332,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+5"/>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -2696,12 +4347,12 @@
<translation>Specify wallet file (within data directory)</translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>The source code is available from %s.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+16"/>
<source>Unable to bind to %s on this computer. %s is probably already running.</source>
<translation type="unfinished"></translation>
</message>
@@ -2727,6 +4378,11 @@
</message>
<message>
<location line="+1"/>
+ <source>Use the test chain</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished"></translation>
</message>
@@ -2761,7 +4417,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-321"/>
+ <location line="-358"/>
<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>
@@ -2776,7 +4432,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+9"/>
<source>Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)</source>
<translation type="unfinished"></translation>
</message>
@@ -2786,7 +4442,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
+ <location line="+15"/>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -2796,7 +4452,7 @@
<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>
@@ -2806,7 +4462,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>
@@ -2816,37 +4472,27 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+21"/>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+24"/>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <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="+12"/>
+ <location line="+15"/>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+21"/>
+ <location line="+28"/>
<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="+26"/>
+ <location line="+31"/>
<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>
@@ -2856,12 +4502,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+8"/>
<source>(default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+4"/>
<source>Accept public REST requests (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -2941,12 +4587,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Set maximum BIP141 block cost (default: %d)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+7"/>
<source>Show all debugging options (usage: --help -help-debug)</source>
<translation type="unfinished"></translation>
</message>
@@ -2961,17 +4602,17 @@
<translation>Signing transaction failed</translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+10"/>
<source>The transaction amount is too small to pay the fee</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="+2"/>
<source>This is experimental software.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+4"/>
<source>Tor control port password (default: empty)</source>
<translation type="unfinished"></translation>
</message>
@@ -2986,12 +4627,7 @@
<translation>Transaction amount too small</translation>
</message>
<message>
- <location line="+1"/>
- <source>Transaction amounts must be positive</source>
- <translation>Transaction amounts must be positive</translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+4"/>
<source>Transaction too large for fee policy</source>
<translation type="unfinished"></translation>
</message>
@@ -3011,7 +4647,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>Username for JSON-RPC connections</source>
<translation>Username for JSON-RPC connections</translation>
</message>
@@ -3041,57 +4677,62 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-65"/>
+ <location line="-73"/>
<source>Password for JSON-RPC connections</source>
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
- <location line="-218"/>
+ <location line="-242"/>
<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="+146"/>
+ <location line="+170"/>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
<message>
- <location line="+57"/>
+ <location line="+58"/>
<source>Loading addresses...</source>
<translation>Loading addresses...</translation>
</message>
<message>
- <location line="-264"/>
+ <location line="-291"/>
<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>
<message>
- <location line="+6"/>
+ <location line="+3"/>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
+ <location line="+43"/>
+ <source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+37"/>
- <source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
+ <location line="+2"/>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+21"/>
+ <location line="+24"/>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+3"/>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<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>
@@ -3106,12 +4747,32 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+32"/>
+ <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"/>
+ <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>
+ <message>
+ <location line="+3"/>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+16"/>
+ <location line="+12"/>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <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 type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
<source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
<translation type="unfinished"></translation>
</message>
@@ -3136,27 +4797,32 @@
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+15"/>
+ <source>Warning: Unknown block versions being mined! It&apos;s possible unknown rules are in effect</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+3"/>
- <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. This option can be specified multiple times</source>
+ <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 type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
- <source>Warning: Unknown block versions being mined! It&apos;s possible unknown rules are in effect</source>
+ <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="+3"/>
- <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>
+ <location line="+12"/>
+ <source>%s is set very high!</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+19"/>
+ <location line="+1"/>
<source>(default: %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+8"/>
<source>Always query for peer addresses via DNS lookup (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -3177,6 +4843,11 @@
</message>
<message>
<location line="+7"/>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -3206,7 +4877,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+7"/>
<source>Prepend debug output with timestamp (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -3221,12 +4892,22 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+7"/>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+1"/>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -3251,37 +4932,72 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+1"/>
+ <source>Starting network threads...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+4"/>
+ <source>Transaction amounts must not be negative</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Transaction must have at least one recipient</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Unknown network specified in -onlynet: &apos;%s&apos;</source>
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-73"/>
+ <location line="-80"/>
<source>Insufficient funds</source>
<translation>Insufficient funds</translation>
</message>
<message>
- <location line="+13"/>
+ <location line="+14"/>
<source>Loading block index...</source>
<translation>Loading block index...</translation>
</message>
<message>
- <location line="-60"/>
+ <location line="-61"/>
<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="+61"/>
+ <location line="+62"/>
<source>Loading wallet...</source>
<translation>Loading wallet...</translation>
</message>
<message>
- <location line="-54"/>
+ <location line="-55"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
diff --git a/src/qt/locale/bitcoin_en_GB.ts b/src/qt/locale/bitcoin_en_GB.ts
index 1893aaca09..8af5db3e64 100644
--- a/src/qt/locale/bitcoin_en_GB.ts
+++ b/src/qt/locale/bitcoin_en_GB.ts
@@ -41,6 +41,65 @@
<source>&amp;Delete</source>
<translation>&amp;Delete</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Choose the address to send coins to</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Choose the address to receive coins with</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>C&amp;hoose</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Sending addresses</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Receiving addresses</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Copy Address</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copy &amp;Label</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Edit</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Export Address List</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Comma separated file (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Exporting Failed</translation>
+ </message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Address</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(no label)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,7 +119,11 @@
<source>Repeat new passphrase</source>
<translation>Repeat new passphrase</translation>
</message>
-</context>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Encrypt wallet</translation>
+ </message>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -270,34 +333,10 @@
<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>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n hour</numerusform><numerusform>%n hours</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n day</numerusform><numerusform>%n days</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n week</numerusform><numerusform>%n weeks</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 and %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n year</numerusform><numerusform>%n years</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 behind</translation>
@@ -384,7 +423,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -404,10 +443,6 @@
<translation>Amount:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priority:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Fee:</translation>
</message>
@@ -460,10 +495,10 @@
<translation>Confirmed</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Priority</translation>
+ <source>(no label)</source>
+ <translation>(no label)</translation>
</message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -486,7 +521,7 @@
<source>&amp;Address</source>
<translation>&amp;Address</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -609,6 +644,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Last block time</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Hide</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -626,7 +676,7 @@
<source>Select payment request file</source>
<translation>Select payment request file</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -938,6 +988,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -947,11 +1000,7 @@
<source>Node/Service</source>
<translation>Node/Service</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Ping Time</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -990,7 +1039,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 and %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -1194,14 +1253,6 @@
<translation>Clear console</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Disconnect Node</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Ban Node for</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;hour</translation>
</message>
@@ -1218,10 +1269,6 @@
<translation>1 &amp;year</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Unban Node</translation>
- </message>
- <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Welcome to the %1 RPC console.</translation>
</message>
@@ -1352,7 +1399,7 @@
<source>Remove</source>
<translation>Remove</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1371,7 +1418,26 @@
<source>&amp;Save Image...</source>
<translation>&amp;Save Image...</translation>
</message>
-</context>
+ <message>
+ <source>Address</source>
+ <translation>Address</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>(no label)</translation>
+ </message>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1407,10 +1473,6 @@
<translation>Amount:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priority:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Fee:</translation>
</message>
@@ -1479,10 +1541,6 @@
<translation>(Smart fee not initialised yet. This usually takes a few blocks...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Confirmation time:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1522,6 +1580,10 @@
<source>S&amp;end</source>
<translation>S&amp;end</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation>(no label)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1601,7 +1663,10 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1699,7 +1764,7 @@
<source>Reset all verify message fields</source>
<translation>Reset all verify message fields</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1715,12 +1780,45 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>This pane shows a detailed description of the transaction</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(no label)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Comma separated file (*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Address</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Exporting Failed</translation>
+ </message>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1729,6 +1827,15 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1763,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>
@@ -1791,10 +1894,6 @@
<translation>Unable to start HTTP server. See debug log for details.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1803,10 +1902,6 @@
<translation>The %s developers</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</translation>
- </message>
- <message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
<translation>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</translation>
</message>
@@ -1827,10 +1922,6 @@
<translation>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
<translation>Error loading %s: You can't enable HD on a already existing non-HD wallet</translation>
</message>
@@ -1843,10 +1934,6 @@
<translation>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</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>
</message>
@@ -1871,10 +1958,6 @@
<translation>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</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>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation>
- </message>
- <message>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
<translation>Unable to rewind the database to a pre-fork state. You will need to re-download the blockchain</translation>
</message>
@@ -1883,18 +1966,6 @@
<translation>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</translation>
</message>
<message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</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>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</translation>
- </message>
- <message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</translation>
- </message>
- <message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation>You need to rebuild the database using -reindex-chainstate to change -txindex</translation>
</message>
@@ -1931,10 +2002,6 @@
<translation>Change index out of range</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Connect only to the specified node(s)</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Connection options:</translation>
</message>
@@ -2055,10 +2122,6 @@
<translation>Location of the auth cookie (default: data dir)</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>Minimum bytes per sigop in transactions we relay and mine (default: %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>Not enough file descriptors available.</translation>
</message>
@@ -2099,10 +2162,6 @@
<translation>Set database cache size in megabytes (%d to %d, default: %d)</translation>
</message>
<message>
- <source>Set maximum block cost (default: %d)</source>
- <translation>Set maximum block cost (default: %d)</translation>
- </message>
- <message>
<source>Set maximum block size in bytes (default: %d)</source>
<translation>Set maximum block size in bytes (default: %d)</translation>
</message>
@@ -2207,10 +2266,6 @@
<translation>Maximum size of data in data carrier transactions we relay and mine (default: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Randomise credentials for every proxy connection. This enables Tor stream isolation (default: %u)</translation>
</message>
@@ -2223,10 +2278,6 @@
<translation>The transaction amount is too small to send after the fee has been deducted</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</translation>
- </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>
</message>
@@ -2339,10 +2390,6 @@
<translation>Transaction amount too small</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Transaction amounts must be positive</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transaction too large for fee policy</translation>
</message>
@@ -2407,14 +2454,14 @@
<translation>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</translation>
</message>
<message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</translation>
+ </message>
+ <message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</translation>
</message>
@@ -2459,10 +2506,6 @@
<translation>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)</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. This option can be specified multiple times</source>
- <translation>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. This option can be specified multiple times</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</translation>
</message>
@@ -2531,8 +2574,8 @@
<translation>Set key pool size to &lt;n&gt; (default: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Set minimum block size in bytes (default: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Set maximum BIP141 block weight (default: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts
index 4471aeb72e..b4ed5e7fd5 100644
--- a/src/qt/locale/bitcoin_eo.ts
+++ b/src/qt/locale/bitcoin_eo.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Forigi</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Ripetu la novan pasfrazon</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -239,30 +242,6 @@
<translation>&amp;Komandliniaj agordaĵoj</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Neniu fonto de blokoj trovebla...</translation>
- </message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n horo</numerusform><numerusform>%n horoj</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n tago</numerusform><numerusform>%n tagoj</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n semajno</numerusform><numerusform>%n semajnoj</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 kaj %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n jaro</numerusform><numerusform>%n jaroj</numerusform></translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>mankas %1</translation>
</message>
@@ -340,7 +319,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Monujo estas &lt;b&gt;ĉifrita&lt;/b&gt; kaj aktuale &lt;b&gt;ŝlosita&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -356,10 +335,6 @@
<translation>Sumo:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritato:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Krompago:</translation>
</message>
@@ -411,11 +386,7 @@
<source>Confirmed</source>
<translation>Konfirmita</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioritato</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -438,7 +409,7 @@
<source>&amp;Address</source>
<translation>&amp;Adreso</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -509,6 +480,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formularo</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Horo de la lasta bloko</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -526,7 +508,7 @@
<source>Select payment request file</source>
<translation>Elektu la dosieron de la pagpeto</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -710,6 +692,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -738,6 +723,16 @@
<source>N/A</source>
<translation>neaplikebla</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 kaj %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -920,7 +915,7 @@
<source>Remove</source>
<translation>Forigi</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -939,7 +934,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Konservi Bildon...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -971,10 +969,6 @@
<translation>Sumo:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritato:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Krompago:</translation>
</message>
@@ -1022,7 +1016,7 @@
<source>S&amp;end</source>
<translation>Ŝendi</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1077,7 +1071,10 @@
<source>Memo:</source>
<translation>Memorando:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1155,7 +1152,7 @@
<source>Reset all verify message fields</source>
<translation>Reagordigi ĉiujn prikontrolajn kampojn</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1171,16 +1168,34 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Tiu ĉi panelo montras detalan priskribon de la transakcio</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1207,10 +1222,6 @@
<translation>Ruli fone kiel demono kaj akcepti komandojn</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Akcepti konektojn el ekstere (defaŭlte: 1 se ne estas -proxy nek -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Kerno de Bitmono</translation>
</message>
@@ -1223,18 +1234,6 @@
<translation>Plenumi komandon kiam monuja transakcio ŝanĝiĝas (%s en cmd anstataŭiĝas per TxID)</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>Tiu ĉi estas antaŭeldona testa versio - uzu laŭ via propra risko - ne uzu por minado aŭ por aplikaĵoj por vendistoj</translation>
- </message>
- <message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Averto: La reto ne tute konsentas! Kelkaj minantoj ŝajne spertas problemojn aktuale.</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>Averto: ŝajne ni ne tute konsentas kun niaj samtavolanoj! Eble vi devas ĝisdatigi vian klienton, aŭ eble aliaj nodoj faru same.</translation>
- </message>
- <message>
<source>&lt;category&gt; can be:</source>
<translation>&lt;category&gt; povas esti:</translation>
</message>
@@ -1243,10 +1242,6 @@
<translation>Blok-kreaj agordaĵoj:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Konekti nur al specifita(j) nodo(j)</translation>
- </message>
- <message>
<source>Corrupted block database detected</source>
<translation>Difektita blokdatumbazo trovita</translation>
</message>
@@ -1339,10 +1334,6 @@
<translation>Transakcia sumo tro malgranda</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Transakcia sumo devas esti pozitiva</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>Transakcio estas tro granda</translation>
</message>
diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts
index c67016637b..fc71bf841b 100644
--- a/src/qt/locale/bitcoin_es.ts
+++ b/src/qt/locale/bitcoin_es.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Eliminar</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Seleccione la dirección a la que enviar monedas</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Seleccione la dirección de la que recibir monedas</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>E&amp;scoger</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Direcciones de envío</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Direcciones de recepción</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>Estas son sus direcciones Bitcoin para enviar pagos. Verifique siempre la cantidad y la dirección de recepción antes de enviar bitcoins.</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>Estas son sus direcciones Bitcoin para recibir pagos. Se recomienda utilizar una nueva dirección de recepción para cada transacción</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Copiar Dirección</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copiar &amp;Etiqueta</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Editar</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exportar lista de direcciones</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Archivo separado de coma (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Falló la exportación</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Había un error intentando guardar la lista de direcciones en %1. Por favor inténtelo de nuevo.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Dirección</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sin etiqueta)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>Repita la nueva contraseña</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>Introduzca la nueva contraseña del monedero. &lt;br/&gt;Por favor utilice una contraseña de &lt;b&gt;diez o más carácteres aleatorios&lt;/b&gt;, o &lt;b&gt;ocho o más palabras&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Cifrar monedero</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Esta operación necesita su contraseña de monedero para desbloquear el monedero.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Desbloquear monedero</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Esta operación necesita su contraseña para descifrar el monedero.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Descifrar monedero</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Cambiar contraseña</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Introduzca la contraseña antigua y la nueva para el monedero.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Confirmar cifrado del monedero</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>Advertencia: Si cifra su monedero y pierde su contraseña&lt;b&gt;¡PERDERÁ TODOS SUS BITCOINS!&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>¿Seguro que desea cifrar su monedero?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Monedero cifrado</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 se cerrará ahora para terminar el proceso de cifrado. Recuerde que cifrar su monedero no puede proteger completamente su monedero de ser robado por malware que infecte su ordenador.</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: Cualquier copia de seguridad anterior que haya hecho en su archivo de monedero debería ser reemplazada con el archivo de monedero cifrado generado recientemente. Por razones de seguridad, las copias de seguridad anteriores del archivo de monedero descifrado serán inútiles en cuanto empiece a utilizar el nuevo monedero cifrado.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Fracasó el cifrado del monedero</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Falló el cifrado del monedero debido a un error interno. Su monedero no fue cifrado.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>La contraseña introducida no coincide.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Fracasó el desbloqueo del monedero</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>La contraseña introducida para el cifrado del monedero es incorrecta.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Fracasó el cifrado del monedero</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>La contraseña del monedero se ha cambiado con éxito.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Alerta: ¡La clave de bloqueo Caps está activa!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -159,6 +318,22 @@
<translation>Abrir &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Pulsar para deshabilitar la actividad de red.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Actividad de red deshabilitada.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <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>
@@ -270,34 +445,10 @@
<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>
</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 día</numerusform><numerusform>%n días</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 y %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n año</numerusform><numerusform>%n años</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 atrás</translation>
@@ -377,6 +528,14 @@
<translation>Transacción entrante</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>La generación de clave HD está &lt;b&gt;habilitada&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>La generación de clave HD está &lt;b&gt;deshabilitada&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>El monedero está &lt;b&gt;cifrado&lt;/b&gt; y actualmente &lt;b&gt;desbloqueado&lt;/b&gt;</translation>
</message>
@@ -384,6 +543,10 @@
<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>
+ <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 seguir seguro y se cerrará.</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -404,10 +567,6 @@
<translation>Cuantía:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridad:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Tasa:</translation>
</message>
@@ -460,8 +619,84 @@
<translation>Confirmado</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Prioridad</translation>
+ <source>Copy address</source>
+ <translation>Copiar ubicación</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copiar ID de transacción</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Bloquear lo no gastado</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Desbloquear lo no gastado</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copiar comisión</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copiar después de couta</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copiar bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copiar polvo</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copiar cambio</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 bloqueado)</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>Esta etiqueta se vuelve roja si algún destinatario recibe una cantidad inferior a la actual puerta polvorienta.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Puede variar +/- %1 satoshi(s) por entrada.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sin etiqueta)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>cambia desde %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(cambio)</translation>
</message>
</context>
<context>
@@ -486,6 +721,38 @@
<source>&amp;Address</source>
<translation>&amp;Dirección</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nueva dirección de recivimiento</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nueva dirección de envío</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Editar dirección de recivimiento</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Editar dirección de envío</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>La dirección introducida "%1" no es una dirección Bitcoin válida.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>La dirección introducida "%1" está ya en la agenda.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Podría no desbloquear el monedero.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Falló la generación de la nueva clave.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -499,7 +766,7 @@
</message>
<message>
<source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
- <translation>El directorio ya existe. Añada %1 si pretende crear aquí un directorio nuevo.</translation>
+ <translation>El directorio ya existe. Añada %1 si pretende crear un directorio nuevo.</translation>
</message>
<message>
<source>Path already exists, and is not a directory.</source>
@@ -557,6 +824,10 @@
<translation>Establecer los certificados raíz SSL para solicitudes de pago (predeterminado: -system-)</translation>
</message>
<message>
+ <source>Show splash screen on startup (default: %u)</source>
+ <translation>Mostrar pantalla de bienvenida en el inicio (predeterminado: %u)</translation>
+ </message>
+ <message>
<source>Reset all settings changed in the GUI</source>
<translation>Reiniciar todos los ajustes modificados en el GUI</translation>
</message>
@@ -573,7 +844,7 @@
</message>
<message>
<source>As this is the first time the program is launched, you can choose where %1 will store its data.</source>
- <translation>Al ser la primera vez que se ejecuta el programa, puede elegir donde %1 almacenara sus datos</translation>
+ <translation>Al ser la primera vez que se ejecuta el programa, puede elegir donde %1 almacenará sus datos.</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>
@@ -605,6 +876,57 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulario</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>Las transacciones recientes aún no pueden ser visibles, y por lo tanto el saldo de su monedero podría ser incorrecto. Esta información será correcta cuando su monedero haya terminado de sincronizarse con la red de bitcoin, como se detalla abajo.</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>La red no aceptará el intentar gastar bitcoins que están afectados por transacciones aún no mostradas.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Número de bloques dejados</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>Avance 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 la sincronización</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Ocultar</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Desconocido. Sincronizando cabeceras (%1)...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -622,6 +944,10 @@
<source>Select payment request file</source>
<translation>Seleccionar archivo de sulicitud de pago</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Seleccionar el archivo de solicitud de pago para abrir</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -643,7 +969,7 @@
</message>
<message>
<source>Size of &amp;database cache</source>
- <translation>Tamaño de cache de la &amp;base de datos</translation>
+ <translation>Tamaño del cache de la &amp;base de datos</translation>
</message>
<message>
<source>MB</source>
@@ -707,7 +1033,7 @@
</message>
<message>
<source>Enable coin &amp;control features</source>
- <translation>Habilitar funcionalidad de &amp;coin control</translation>
+ <translation>Habilitar funcionalidad de &amp;Coin Control</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>
@@ -811,7 +1137,7 @@
</message>
<message>
<source>&amp;Unit to show amounts in:</source>
- <translation>Mostrar las cantidades en la &amp;unidad:</translation>
+ <translation>&amp;Unidad en la cual mostrar las cantidades:</translation>
</message>
<message>
<source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
@@ -835,7 +1161,7 @@
</message>
<message>
<source>none</source>
- <translation>ninguna</translation>
+ <translation>Ninguna</translation>
</message>
<message>
<source>Confirm options reset</source>
@@ -934,6 +1260,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Fallo en la solicitud de pago</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>No se puede iniciar bitcoin: encargado click-para-pagar</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Manejo de URI</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>La búsqueda de solicitud de pago URL es válida: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Dirección de pago inválida %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 no puede ser analizado! Esto puede ser causado por una dirección Bitcoin inválida o parametros URI mal formados.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Manejo del archivo de solicitud de pago</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>¡El archivo de solicitud de pago no puede ser leído! Esto puede ser causado por un archivo de solicitud de pago inválido.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Solicitud de pago rechazada</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>La red de solicitud de pago no cimbina la red cliente.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Solicitud de pago caducada.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>La solicitud de pago no se ha iniciado.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Solicitudes de pago sin verificar a scripts de pago habitual no se soportan.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Solicitud de pago inválida.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Cantidad de pago solicitada de %1 es demasiado pequeña (considerado polvo).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Reembolsar desde %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>Solicitud de pago de %1 es demasiado grande (%2 bytes, permitidos %3 bytes).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Fallo al comunicar con %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>¡La solicitud de pago no puede ser analizada!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Mala respuesta desde el servidor %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Fallo de solicitud de red</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Pago declarado</translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -944,8 +1361,12 @@
<translation>Nodo/Servicio</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Ping</translation>
+ <source>NodeId</source>
+ <translation>ID de nodo</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Sonido</translation>
</message>
</context>
<context>
@@ -986,6 +1407,72 @@
<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 y %2</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n año</numerusform><numerusform>%n años</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 no se ha cerrado de forma segura todavía...</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Error: El directorio de datos «%1» especificado no existe.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>Error: No se puede analizar el archivo de configuración: %1. Utilice únicamente la sintaxis clave=valor.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Error: %1</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Guardar imagen...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Copiar imagen</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Guardar código QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Imagen PNG (*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1146,6 +1633,10 @@
<translation>Espera de Ping</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Sonido Mínimo</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Desplazamiento de tiempo</translation>
</message>
@@ -1190,14 +1681,6 @@
<translation>Borrar consola</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>Nodo &amp;Desconectado</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Prohibir Nodo para</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;hora</translation>
</message>
@@ -1214,8 +1697,16 @@
<translation>1 &amp;año</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Desbanear Nodo</translation>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Desconectar</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Prohibir para</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Unbano</translation>
</message>
<message>
<source>Welcome to the %1 RPC console.</source>
@@ -1230,6 +1721,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: Los estafadores han sido activados, diciéndoles a los usuarios que escriban comandos aquí, 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>
@@ -1348,6 +1847,22 @@
<source>Remove</source>
<translation>Eliminar</translation>
</message>
+ <message>
+ <source>Copy URI</source>
+ <translation>Copiar URI</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar capa</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Copiar imagen</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar cantidad</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1367,6 +1882,73 @@
<source>&amp;Save Image...</source>
<translation>Guardar Imagen...</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Solicitar pago a %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Información de pago</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Dirección</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Cantidad</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mensaje</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>URI resultante demasiado grande, trate de reducir el texto de etiqueta / mensaje.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Fallo al codificar URI en código QR.</translation>
+ </message>
+</context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Fecha</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mensaje</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sin etiqueta)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(no hay mensaje)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(no hay solicitud de cantidad)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Solicitado</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1403,10 +1985,6 @@
<translation>Cuantía:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridad:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Tasa:</translation>
</message>
@@ -1436,7 +2014,7 @@
</message>
<message>
<source>collapse fee-settings</source>
- <translation>Colapsar ajustes de cuota</translation>
+ <translation>Colapsar ajustes de comisión.</translation>
</message>
<message>
<source>per kilobyte</source>
@@ -1444,7 +2022,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>Si la tarifa de aduana se establece en 1000 satoshis y la transacción está a sólo 250 bytes, entonces "por kilobyte" sólo paga 250 satoshis de cuota, mientras que "el mínimo total" pagaría 1.000 satoshis. Para las transacciones más grandes que un kilobyte ambos pagan por kilobyte</translation>
+ <translation>Si la comisión se establece en 1000 satoshis y la transacción está a sólo 250 bytes, entonces "por kilobyte" sólo paga 250 satoshis de cuota, mientras que "el mínimo total" pagaría 1.000 satoshis. Para las transacciones más grandes que un kilobyte ambos pagan por kilobyte</translation>
</message>
<message>
<source>Hide</source>
@@ -1456,7 +2034,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>Pagando solamente la cuota mínima es correcto, siempre y cuando haya menos volumen de transacciones que el espacio en los bloques. Pero tenga en cuenta que esto puede terminar en una transacción nunca confirmada, una vez que haya más demanda para transacciones Bitcoin que la red pueda procesar.</translation>
+ <translation>Pagar solamente la comisión mínima es correcto, siempre y cuando haya menos volumen de transacciones que el espacio en los bloques. Pero tenga en cuenta que esto puede terminar en una transacción nunca confirmada, una vez que haya más demanda para transacciones Bitcoin que la red pueda procesar.</translation>
</message>
<message>
<source>(read the tooltip)</source>
@@ -1464,19 +2042,15 @@
</message>
<message>
<source>Recommended:</source>
- <translation>Recomendado:</translation>
+ <translation>Recomendada:</translation>
</message>
<message>
<source>Custom:</source>
- <translation>Personalizado:</translation>
+ <translation>Personalizada:</translation>
</message>
<message>
<source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
- <translation>(Tarifa inteligente no inicializado aún. Esto generalmente lleva a pocos bloques...)</translation>
- </message>
- <message>
- <source>Confirmation time:</source>
- <translation>Tiempo de confirmación:</translation>
+ <translation>(Aún no se ha inicializado la Comisión Inteligente. Esto generalmente tarda pocos bloques...)</translation>
</message>
<message>
<source>normal</source>
@@ -1503,6 +2077,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>
@@ -1518,6 +2096,126 @@
<source>S&amp;end</source>
<translation>&amp;Enviar</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copiar comisión</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copiar después de couta</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copiar bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copiar polvo</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copiar cambio</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>¿Seguro que quiere enviar?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>añadido como comisión de transacción</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Cantidad total %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>o</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Confirmar enviar monedas</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>La dirección de destinatario no es válida. Por favor revísela.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>La cantidad a pagar debe de ser mayor que 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>La cantidad excede su saldo.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>El total excede su saldo cuando la comisión de transacción de %1 es incluida.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Dirección duplicada encontrada: la dirección sólo debería ser utilizada una vez por cada uso.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <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>
+ <message>
+ <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>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <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>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1563,11 +2261,11 @@
</message>
<message>
<source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
- <translation>La cuota será deducida de la cantidad que sea mandada. El destinatario recibirá menos bitcoins de los que entres en el </translation>
+ <translation>La comisión será deducida de la cantidad que sea mandada. El destinatario recibirá menos bitcoins de la cantidad introducida en el campo Cantidad. Si hay varios destinatarios, la comisión será distribuida a partes iguales.</translation>
</message>
<message>
<source>S&amp;ubtract fee from amount</source>
- <translation>Restar comisiones a la cantidad</translation>
+ <translation>Restar comisiones de la cantidad.</translation>
</message>
<message>
<source>Message:</source>
@@ -1597,6 +2295,17 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Introduzca una etiqueta para esta dirección para añadirla a su lista de direcciones.</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Sí</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1695,6 +2404,58 @@
<source>Reset all verify message fields</source>
<translation>Vaciar todos los campos de la verificación de mensaje</translation>
</message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Click en "Fírmar mensaje" para generar una firma</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>La dirección introducida no es válida.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Por favor revise la dirección e inténtelo de nuevo.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>La dirección introducida no remite a una clave.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>El desbloqueo del monedero fue cancelado.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>La clave privada de la dirección introducida no está disponible.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Falló la firma del mensaje.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Mensaje firmado.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>La firma no pudo descodificarse.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Por favor compruebe la firma y pruebe de nuevo.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>La firma no se combinó con el mensaje.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Falló la verificación del mensaje.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Mensaje verificado.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1711,11 +2472,440 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Open until %1</source>
+ <translation>Abierto hasta %1</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>Hay un conflicto con la traducción de las confirmaciones %1</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/sin conexión</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/no confirmado, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>en el equipo de memoria</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>no en el equipo de memoria</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>abandonado</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/no confirmado</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>confirmaciones %1</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Estado</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, no ha sido emitido con éxito aún</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Fecha</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Fuente</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Generado</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Desde</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconocido</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Para</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>dirección propia</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>de observación</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etiqueta</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Credito</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>no aceptada</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Enviado</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Total enviado</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Total recibido</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Comisión de transacción</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Cantidad neta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mensaje</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Comentario</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>Identificador de transacción (ID)</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Indice de salida</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Vendedor</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>Los bitcoins generados deben madurar %1 bloques antes de que puedan gastarse. Cuando generó este bloque, se transmitió a la red para que se añadiera a la cadena de bloques. Si no consigue entrar en la cadena, su estado cambiará a "no aceptado" y ya no se podrá gastar. Esto puede ocurrir ocasionalmente si otro nodo genera un bloque a pocos segundos del suyo.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Información de depuración</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transacción</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>entradas</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Cantidad</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>verdadero</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 ventana muestra información detallada sobre la transacción</translation>
</message>
+ <message>
+ <source>Details for %1</source>
+ <translation>Detalles para %1</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Fecha</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>Abierto hasta %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Sin conexion</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Sin confirmar</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Abandonado</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Confirmando (%1 de %2 confirmaciones recomendadas)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Confirmado (%1 confirmaciones)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>En conflicto</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>No disponible (%1 confirmaciones. Estarán disponibles al cabo de %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Este bloque no ha sido recibido por otros nodos y probablemente no sea aceptado!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Generado pero no aceptado</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Recibido con</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Recibidos de</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviado a</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Pago proprio</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minado</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>de observación</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(nd)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sin etiqueta)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Estado de transacción. Pasa el ratón sobre este campo para ver el número de confirmaciones.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Fecha y hora en que se recibió la transacción.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Tipo de transacción.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Si una dirección watch-only está involucrada en esta transacción o no.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Descripción de la transacción definido por el usuario.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Cantidad retirada o añadida al saldo.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Todo</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Hoy</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Esta semana</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Este mes</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Mes pasado</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Este año</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Rango...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Recibido con</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviado a</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>A usted mismo</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minado</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Otra</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Introduzca una dirección o etiqueta que buscar</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Cantidad mínima</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Transacción abandonada</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Copiar ubicación</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar capa</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copiar ID de transacción</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Copiar transacción raw</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Copiar todos los detalles de la transacción</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Editar etiqueta</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Mostrar detalles de la transacción</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exportar historial de transacciones</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Archivo separado de coma (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Confirmado</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>De observación</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Fecha</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipo</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Dirección</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Falló la exportación</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Ha habido un error al intentar guardar la transacción con %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Exportación finalizada</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>La transacción ha sido guardada en %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Rango:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>para</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1725,6 +2915,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>No se ha cargado ningún monedero</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Enviar</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 a un archivo los datos de esta pestaña</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Copia de seguridad del monedero</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Datos de monedero (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>La copia de seguridad ha fallado</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Ha habido un error al intentar guardar los datos del monedero en %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Se ha completado con éxito la copia de respaldo</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Los datos del monedero se han guardado con éxito en %1.</translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1758,11 +2997,7 @@
</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>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>
+ <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>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
@@ -1790,20 +3025,12 @@
<translation>No se ha podido comenzar el servidor HTTP. Ver debug log para detalles.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Aceptar conexiones desde el exterior (predeterminado: 1 si no -proxy o -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
<source>The %s developers</source>
- <translation>Los %s desarrolladores</translation>
- </message>
- <message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee tiene un ajuste muy alto! Esta es la comisión de transacción que pagarás cuando las estimaciones de comisiones no estén disponibles.</translation>
+ <translation>Los desarrolladores 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>
@@ -1826,10 +3053,6 @@
<translation>Borrar todas las transacciones del monedero y sólo recuperar aquellas partes de la cadena de bloques por medio de -rescan on startup.</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuido bajo la licencia de software MIT, vea la copia del archivo adjunto o &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
<translation>Error cargando %s: No puede habilitar HD en un monedero existente que no es HD</translation>
</message>
@@ -1842,16 +3065,12 @@
<translation>Ejecutar comando cuando una transacción del monedero cambia (%s en cmd se remplazará por TxID)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Fuerza la retransmisión de transacciones desde nodos en la lista blanca incluso si violan la política de retransmisiones local (predeterminado: %d)</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>
<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>Máximas comisiones totales (en %s) para utilizar en una sola transacción de la cartera; establecer esto demasiado bajo puede abortar grandes transacciones (predeterminado: %s)</translation>
+ <translation>Máximas comisiones totales (en %s) para utilizar en una sola transacción del monedero; establecer esto demasiado bajo puede abortar grandes transacciones (predeterminado: %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>
@@ -1870,10 +3089,6 @@
<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 pre-prueba - utilícela bajo su propio riesgo. No la utilice para usos comerciales o de minería.</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>
@@ -1882,18 +3097,6 @@
<translation>Utiliza UPnP para asignar el puerto de escucha (predeterminado: 1 cuando esta escuchando sin -proxy)</translation>
</message>
<message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Atención: ¡Parece que la red no está totalmente de acuerdo! Algunos mineros están presentando inconvenientes.</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>Atención: ¡Parece que no estamos completamente de acuerdo con nuestros pares! Podría necesitar una actualización, u otros nodos podrían necesitarla.</translation>
- </message>
- <message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Poner en lista blanca a los equipos que se conecten desde la máscara de subred o dirección IP especificada. Se puede especificar múltiples veces.</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>
@@ -1930,10 +3133,6 @@
<translation>Cambio de indice fuera de rango</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Conectar sólo a los nodos (o nodo) especificados</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Opciones de conexión:</translation>
</message>
@@ -2054,10 +3253,6 @@
<translation>Ubicación de la cookie de autenticación (default: data dir)</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>Mínimo de bytes por sigop en transacciones que retransmitimos y minamos (predeterminado: %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>No hay suficientes descriptores de archivo disponibles. </translation>
</message>
@@ -2095,11 +3290,7 @@
</message>
<message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
- <translation>Asignar tamaño de cache en megabytes (entre %d y %d; predeterminado: %d)</translation>
- </message>
- <message>
- <source>Set maximum block cost (default: %d)</source>
- <translation>Establecer tamaño máximo de bloque (por defecto: %d)</translation>
+ <translation>Asignar tamaño del cache en megabytes (entre %d y %d; predeterminado: %d)</translation>
</message>
<message>
<source>Set maximum block size in bytes (default: %d)</source>
@@ -2199,17 +3390,13 @@
</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>Cantidad no válida para -maxtxfee=&lt;amount&gt;: '%s' (debe ser por lo menos la cuota de comisión mínima de %s para prevenir transacciones atascadas)</translation>
+ <translation>Cantidad no válida para -maxtxfee=&lt;amount&gt;: '%s' (debe ser por lo menos la comisión mínima de %s para prevenir transacciones atascadas)</translation>
</message>
<message>
<source>Maximum size of data in data carrier transactions we relay and mine (default: %u)</source>
<translation>El tamaño máximo de los datos en las operaciones de transporte de datos que transmitimos y el mio (default: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Consulta de direcciones pares mediante búsqueda de DNS, si bajo en direcciones (por defecto: 1 a menos que - conectar)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Aleatorizar las credenciales para cada conexión proxy. Esto habilita la Tor stream isolation (por defecto: %u)</translation>
</message>
@@ -2222,10 +3409,6 @@
<translation>Monto de transacción muy pequeña luego de la deducción por comisión</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Este producto incluye software desarrollado por el OpenSSL Project para su uso en OpenSSL Toolkit &lt;https://www.openssl.org/&gt;, software de cifrado escrito por Eric Young y software UPnP escrito por Thomas Bernard.</translation>
- </message>
- <message>
<source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
<translation>Usar tras BIP32 la generación de llave determinística jerárquica (HD) . Solo tiene efecto durante el primer inicio/generación del monedero</translation>
</message>
@@ -2295,7 +3478,7 @@
</message>
<message>
<source>Rescan the block chain for missing wallet transactions on startup</source>
- <translation>Rescanea la cadena de bloques para transacciones perdidas de la cartera</translation>
+ <translation>Rescanea la cadena de bloques para buscar transacciones perdidas del monedero</translation>
</message>
<message>
<source>Send trace/debug info to console instead of debug.log file</source>
@@ -2338,16 +3521,12 @@
<translation>Cantidad de la transacción demasiado pequeña</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Las cantidades en las transacciones deben ser positivas</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Operación demasiado grande para la política de tasas</translation>
</message>
<message>
<source>Transaction too large</source>
- <translation>Transacción demasiado grande</translation>
+ <translation>Transacción demasiado grande, intenta dividirla en varias.</translation>
</message>
<message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
@@ -2355,7 +3534,7 @@
</message>
<message>
<source>Upgrade wallet to latest format on startup</source>
- <translation>Actualizar el monedero al último formato</translation>
+ <translation>Actualizar el monedero al último formato al inicio</translation>
</message>
<message>
<source>Username for JSON-RPC connections</source>
@@ -2401,25 +3580,29 @@
</message>
<message>
<source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
- <translation>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</translation>
+ <translation>(1 = mantener los meta datos de transacción, por ejemplo: propietario e información de pago, 2 = omitir los metadatos)</translation>
</message>
<message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
- <translation>-maxtxfee tiene un ajuste muy elevado! Las comisiones así de grandes podrían ser pagadas en una única transaccion.</translation>
- </message>
- <message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee tiene un ajuste muy elevado! Esta es la comisión de transacción que pagaras si envías una transaccion.</translation>
+ <translation>-maxtxfee tiene un ajuste muy elevado! Comisiones muy grandes podrían ser pagadas en una única transaccion.</translation>
</message>
<message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>No mantener transacciones en la memoria mas de &lt;n&gt; horas (predeterminado: %u)</translation>
</message>
<message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Bytes equivalentes por sigop en transacciones para retrasmisión y minado (predeterminado: %u)</translation>
+ </message>
+ <message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation>Las comisiones (en %s/kB) menores que esto son consideradas de cero comision para la creacion de transacciones (predeterminado: %s)</translation>
</message>
<message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>Fuerza la retransmisión de transacciones desde nodos en la lista blanca incluso si violan la política de retransmisiones local (predeterminado: %d)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>Nivel de rigor en la verificación de bloques de -checkblocks (0-4; predeterminado: %u)</translation>
</message>
@@ -2436,8 +3619,25 @@
<translation>Mostrar depuración (por defecto: %u, proporcionar &lt;category&gt; es opcional)</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>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>
+ <message>
+ <source>Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)</source>
+ <translation>Intenta de mantener el Tráfico de salida , bajo el Objetivo Determinado (en MiB por 24h) , 0 = sin limite (Por Defecto :%d )</translation>
+ </message>
+ <message>
<source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source>
- <translation>Error: Unsupported argumento -socks encontrados. SOCKS versión ajuste ya no es posible, sólo SOCKS5 proxies son compatibles.</translation>
+ <translation>Error: argumento -socks encontrado. El ajuste de la versión SOCKS ya no es posible, sólo proxies SOCKS5 son compatibles.</translation>
</message>
<message>
<source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
@@ -2448,10 +3648,6 @@
<translation>Usar distintos proxys SOCKS5 para comunicarse vía Tor de forma anónima (Por defecto: %s)</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. This option can be specified multiple times</source>
- <translation>Nombre de usuario y hash de la contraseña para las conexiones JSON-RPC. El campo &lt;userpw&gt; tiene el formato: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Se incluye un script python convencional en share/rpcuser. Esta opción puede ser especificada multiples veces</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>Advertencia: Se están minando versiones de bloques desconocidas! Es posible que normas desconocidas estén activas</translation>
</message>
@@ -2460,6 +3656,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>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>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>(default: %s)</source>
<translation>(predeterminado: %s)</translation>
</message>
@@ -2520,8 +3720,8 @@
<translation>Ajustar el número de claves en reserva &lt;n&gt; (predeterminado: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Establecer tamaño mínimo de bloque en bytes (por defecto: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Establecer peso máximo bloque BIP141 (predeterminado: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
@@ -2541,7 +3741,11 @@
</message>
<message>
<source>Spend unconfirmed change when sending transactions (default: %u)</source>
- <translation>Gastar cambio no confirmado al enviar transacciones (predeterminado: %u)</translation>
+ <translation>Usar cambio aún no confirmado al enviar transacciones (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Starting network threads...</source>
+ <translation>Iniciando funciones de red...</translation>
</message>
<message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
@@ -2569,7 +3773,7 @@
</message>
<message>
<source>Cannot downgrade wallet</source>
- <translation>No se puede rebajar el monedero</translation>
+ <translation>No se puede cambiar a una versión mas antigua el monedero</translation>
</message>
<message>
<source>Cannot write default address</source>
diff --git a/src/qt/locale/bitcoin_es_AR.ts b/src/qt/locale/bitcoin_es_AR.ts
index 40ebaf8856..6a418e645b 100644
--- a/src/qt/locale/bitcoin_es_AR.ts
+++ b/src/qt/locale/bitcoin_es_AR.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Borrar</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Repetí la nueva Frase de Contraseña</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -83,6 +86,9 @@
<name>Intro</name>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -92,12 +98,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -107,12 +122,18 @@
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -125,12 +146,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts
index 188641d6e7..ac01c4219b 100644
--- a/src/qt/locale/bitcoin_es_CL.ts
+++ b/src/qt/locale/bitcoin_es_CL.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Borrar</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -56,7 +59,7 @@
<source>Repeat new passphrase</source>
<translation>Repite nueva contraseña</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -207,10 +210,6 @@
<translation>Pide pagos (genera codigos QR and bitcoin: URls)</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 y %2</translation>
- </message>
- <message>
<source>Error</source>
<translation>Error</translation>
</message>
@@ -246,7 +245,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>La billetera esta &lt;b&gt;codificada&lt;/b&gt; y actualmente &lt;b&gt;bloqueda&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -254,10 +253,6 @@
<translation>Cantidad:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>prioridad:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>comisión:
</translation>
@@ -278,11 +273,7 @@
<source>Confirmed</source>
<translation>Confirmado</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>prioridad</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -297,7 +288,7 @@
<source>&amp;Address</source>
<translation>&amp;Dirección</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -332,6 +323,13 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>URI:</source>
@@ -442,6 +440,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -454,6 +455,16 @@
<source>N/A</source>
<translation>N/A</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 y %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -548,7 +559,10 @@
<source>&amp;Save Image...</source>
<translation>Guardar imagen...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -564,10 +578,6 @@
<translation>Cantidad:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>prioridad:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>comisión:
</translation>
@@ -608,7 +618,7 @@
<source>S&amp;end</source>
<translation>&amp;Envía</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -645,6 +655,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -709,16 +722,34 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Esta ventana muestra información detallada sobre la transacción</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -745,11 +776,6 @@
<translation>bitcoin core</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Conecta solo al nodo especificado
-</translation>
- </message>
- <message>
<source>Error loading block database</source>
<translation>Error cargando blkindex.dat</translation>
</message>
diff --git a/src/qt/locale/bitcoin_es_CO.ts b/src/qt/locale/bitcoin_es_CO.ts
index df189190f6..f993f88605 100644
--- a/src/qt/locale/bitcoin_es_CO.ts
+++ b/src/qt/locale/bitcoin_es_CO.ts
@@ -37,7 +37,10 @@
<source>&amp;Delete</source>
<translation>&amp;Borrar</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -56,7 +59,7 @@
<source>Repeat new passphrase</source>
<translation>Repetir nueva contraseña</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -198,11 +201,18 @@
<context>
<name>Intro</name>
<message>
+ <source>Welcome</source>
+ <translation>bienvenido</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Error</translation>
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -212,12 +222,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -227,12 +246,18 @@
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -245,12 +270,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Bitcoin Core</source>
diff --git a/src/qt/locale/bitcoin_es_DO.ts b/src/qt/locale/bitcoin_es_DO.ts
index ba963d2b80..77e6ef16f3 100644
--- a/src/qt/locale/bitcoin_es_DO.ts
+++ b/src/qt/locale/bitcoin_es_DO.ts
@@ -37,7 +37,10 @@
<source>&amp;Delete</source>
<translation>&amp;Eliminar</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -56,7 +59,7 @@
<source>Repeat new passphrase</source>
<translation>Repita la nueva contraseña</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -235,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>
@@ -286,7 +285,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -302,10 +301,6 @@
<translation>Cuantía:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridad:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Tasa:</translation>
</message>
@@ -345,11 +340,7 @@
<source>Confirmed</source>
<translation>Confirmado</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioridad</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -372,7 +363,7 @@
<source>&amp;Address</source>
<translation>&amp;Dirección</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -435,6 +426,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Desde</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Hora del último bloque</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -452,7 +454,7 @@
<source>Select payment request file</source>
<translation>Seleccione archivo de sulicitud de pago</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -616,6 +618,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -638,6 +643,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>N/A</source>
@@ -798,7 +809,7 @@
<source>Remove</source>
<translation>Eliminar</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -817,7 +828,10 @@
<source>&amp;Save Image...</source>
<translation>Guardar Imagen...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -853,10 +867,6 @@
<translation>Cuantía:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridad:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Tasa:</translation>
</message>
@@ -908,7 +918,7 @@
<source>S&amp;end</source>
<translation>&amp;Enviar</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -963,7 +973,10 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
</context>
@@ -1037,7 +1050,7 @@
<source>Reset all verify message fields</source>
<translation>Limpiar todos los campos de la verificación de mensaje</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1053,16 +1066,34 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Esta ventana muestra información detallada sobre la transacción</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1092,10 +1123,6 @@
</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Aceptar conexiones desde el exterior (predeterminado: 1 si no -proxy o -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Núcleo de Bitcoin</translation>
</message>
@@ -1108,18 +1135,6 @@
<translation>Ejecutar comando cuando una transacción del monedero cambia (%s en cmd se remplazará por TxID)</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 pre-prueba - utilícela bajo su propio riesgo. No la utilice para usos comerciales o de minería.</translation>
- </message>
- <message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Atención: ¡Parece que la red no está totalmente de acuerdo! Algunos mineros están presentando inconvenientes.</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>Atención: ¡Parece que no estamos completamente de acuerdo con nuestros pares! Podría necesitar una actualización, u otros nodos podrían necesitarla.</translation>
- </message>
- <message>
<source>&lt;category&gt; can be:</source>
<translation>&lt;category&gt; puede ser:</translation>
</message>
@@ -1128,10 +1143,6 @@
<translation>Opciones de creación de bloques:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Conectar sólo a los nodos (o nodo) especificados</translation>
- </message>
- <message>
<source>Corrupted block database detected</source>
<translation>Corrupción de base de datos de bloques detectada.</translation>
</message>
@@ -1232,10 +1243,6 @@
<translation>Monto de la transacción muy pequeño</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Montos de transacciones deben ser positivos</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>Transacción demasiado grande</translation>
</message>
diff --git a/src/qt/locale/bitcoin_es_ES.ts b/src/qt/locale/bitcoin_es_ES.ts
index c66a477cc2..7865483183 100644
--- a/src/qt/locale/bitcoin_es_ES.ts
+++ b/src/qt/locale/bitcoin_es_ES.ts
@@ -3,11 +3,11 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Haz clic derecho para editar la dirección o la etiqueta</translation>
+ <translation>Haz clic derecho para editar la dirección o etiqueta</translation>
</message>
<message>
<source>Create a new address</source>
- <translation>Crea una nueva direccióon</translation>
+ <translation>Crear una nueva dirección</translation>
</message>
<message>
<source>&amp;New</source>
@@ -15,7 +15,7 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation>Copia la direccón seleccionada al portapapeles del sistema</translation>
+ <translation>Copiar la dirección seleccionada al portapapeles del sistema</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -27,11 +27,11 @@
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation>Elimina la dirección seleccionada de la lista</translation>
+ <translation>Eliminar la dirección seleccionada de la lista</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation>Exporta los datos de la pestaña actual a un archivo</translation>
+ <translation>Exportar los datos en la ficha actual a un archivo</translation>
</message>
<message>
<source>&amp;Export</source>
@@ -41,16 +41,87 @@
<source>&amp;Delete</source>
<translation>&amp;Eliminar</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Seleccione la dirección a la que enviar monedas</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Seleccione la dirección de la que recibir monedas</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>E&amp;scoger</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Enviando direcciones</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Recibiendo direcciones</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>Estas son sus direcciones Bitcoin para enviar pagos. Verifique siempre la cantidad y la dirección de recibimiento antes de enviar monedas.</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>Estas son sus direcciones Bitcoin para recibir pagos. Se recomienda utilizar una nueva dirección de recibimiento para cada transacción</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Copiar Dirección</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copiar &amp;Etiqueta</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Editar</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exportar lista de direcciones</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Archivo separado de coma (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Falló la exportación</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Había un error intentando guardar la lista de direcciones en %1. Por favor inténtelo de nuevo.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Dirección</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sin etiqueta)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
<message>
<source>Passphrase Dialog</source>
- <translation>Dialogo de Contraseña</translation>
+ <translation>Diálogo de contraseña</translation>
</message>
<message>
<source>Enter passphrase</source>
- <translation>Introduzca la contraseña</translation>
+ <translation>Introducir contraseña</translation>
</message>
<message>
<source>New passphrase</source>
@@ -58,12 +129,108 @@
</message>
<message>
<source>Repeat new passphrase</source>
- <translation>Repite la nueva contraseña</translation>
+ <translation>Repita la nueva contraseña</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>Introduzca la nueva frase clave del monedero. &lt;br/&gt;Por favor utilice una frase clave de &lt;b&gt;diez o más carácteres aleatorios&lt;/b&gt;, o &lt;b&gt;ocho o más palabras&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Monedero encriptado</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Esta operación necesita su frase clave de monedero para desbloquear el monedero.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Desbloquear monedero</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Esta operación necesita su frase clave de cartera para desencriptar el monedero.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Desencriptar monedero</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Cambiar frase clave</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Introduzca la vieja frase clave y la nueva flase clave para el monedero.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Confirmar encriptación del monedero</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>Advertencia: Si encripta su monedero y pierde su frase clave &lt;b&gt;PERDERÁ TODOS SUS BITCOINS&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>¿Seguro que desea encriptar su monedero?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Monedero encriptado</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 se cerrará ahora para terminar el proceso de encriptación. Recuerde que encriptar su monedero no puede proteger completamente su monedero de ser robado por malware que infecte su ordenador.</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: Cualquier copia de seguridad anterior que haya hecho en su archivo de monedero debería ser reemplazada con el archivo de monedero encriptado generado recientemente. Por razones de seguridad, las copias de seguridad anteriores del archivo de monedero desencriptado serán inútiles en cuanto empiece a utilizar el nuevo monedero encriptado.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Fracasó la encriptación de monedero</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Falló la encriptación del monedero debido a un error interno. Su monedero no fue encriptado.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>La frase clave introducida no coincide.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Fracasó el desbloqueo del monedero</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>La frase clave introducida para la encriptación del monedero es incorrecta.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Fracasó la encriptación del monedero</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>La frase clave del monedero se ha cambiado con éxito.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Alerta: ¡La clave de bloqueo Caps está activa!</translation>
</message>
</context>
<context>
<name>BanTableModel</name>
- </context>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Máscara</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Bloqueado Hasta</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
@@ -72,7 +239,7 @@
</message>
<message>
<source>Synchronizing with network...</source>
- <translation>Sincronizando con la red...</translation>
+ <translation>Sincronizando con la red…</translation>
</message>
<message>
<source>&amp;Overview</source>
@@ -84,7 +251,7 @@
</message>
<message>
<source>Show general overview of wallet</source>
- <translation>Mostrar vista general de la cartera</translation>
+ <translation>Mostrar vista general del monedero</translation>
</message>
<message>
<source>&amp;Transactions</source>
@@ -92,7 +259,7 @@
</message>
<message>
<source>Browse transaction history</source>
- <translation>Navegar historial de transacciones</translation>
+ <translation>Examinar el historial de transacciones</translation>
</message>
<message>
<source>E&amp;xit</source>
@@ -103,36 +270,48 @@
<translation>Salir de la aplicación</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>&amp;Acerca de %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Mostrar información acerca de %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>Acerca de &amp;Qt</translation>
</message>
<message>
<source>Show information about Qt</source>
- <translation>Muestra información acerca de Qt</translation>
+ <translation>Mostrar información acerca de Qt</translation>
</message>
<message>
<source>&amp;Options...</source>
<translation>&amp;Opciones...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Modificar las opciones de configuración para %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
- <translation>&amp;Encriptar Cartera...</translation>
+ <translation>&amp;Cifrar monedero…</translation>
</message>
<message>
<source>&amp;Backup Wallet...</source>
- <translation>&amp;Hacer copia de seguridad de la cartera...</translation>
+ <translation>&amp;Guardar copia del monedero...</translation>
</message>
<message>
<source>&amp;Change Passphrase...</source>
- <translation>&amp;Cambiar contraseña...</translation>
+ <translation>&amp;Cambiar la contraseña…</translation>
</message>
<message>
<source>&amp;Sending addresses...</source>
- <translation>&amp;Enviando direcciones...</translation>
+ <translation>Direcciones de &amp;envío...</translation>
</message>
<message>
<source>&amp;Receiving addresses...</source>
- <translation>&amp;Recibiendo direcciones..</translation>
+ <translation>Direcciones de &amp;recepción...</translation>
</message>
<message>
<source>Open &amp;URI...</source>
@@ -140,93 +319,3300 @@
</message>
<message>
<source>Reindexing blocks on disk...</source>
- <translation>Reindexando bloques en el disco...</translation>
+ <translation>Reindexando bloques en disco...</translation>
</message>
<message>
<source>Send coins to a Bitcoin address</source>
- <translation>Envia monedas a una dirección Bitcoin</translation>
+ <translation>Enviar bitcoins a una dirección Bitcoin</translation>
</message>
<message>
<source>Backup wallet to another location</source>
- <translation>Crea una copia de seguridad de tu cartera en otra ubicación</translation>
+ <translation>Copia de seguridad del monedero en otra ubicación</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation>Cambiar la contraseña utilizada para el cifrado del monedero</translation>
+ </message>
+ <message>
+ <source>&amp;Debug window</source>
+ <translation>&amp;Ventana de depuración</translation>
+ </message>
+ <message>
+ <source>Open debugging and diagnostic console</source>
+ <translation>Abrir la consola de depuración y diagnóstico</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message...</source>
+ <translation>&amp;Verificar mensaje...</translation>
+ </message>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Monedero</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation>&amp;Enviar</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation>&amp;Recibir</translation>
+ </message>
+ <message>
+ <source>&amp;Show / Hide</source>
+ <translation>&amp;Mostrar / Ocultar</translation>
+ </message>
+ <message>
+ <source>Show or hide the main Window</source>
+ <translation>Mostrar u ocultar la ventana principal</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation>Cifrar las claves privadas de su monedero</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation>Firmar mensajes con sus direcciones Bitcoin para demostrar la propiedad</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation>Verificar mensajes comprobando que están firmados con direcciones Bitcoin concretas</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation>&amp;Archivo</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation>&amp;Configuración</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation>&amp;Ayuda</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation>Barra de pestañas</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation>Solicitar pagos (generando códigos QR e identificadores URI "bitcoin:")</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation>Mostrar la lista de direcciones de envío y etiquetas</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation>Muestra la lista de direcciones de recepción y etiquetas</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI or payment request</source>
+ <translation>Abrir un identificador URI "bitcoin:" o una petición de pago</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation>&amp;Opciones de consola de comandos</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network</source>
+ <translation><numerusform>%n conexión activa hacia la red Bitcoin</numerusform><numerusform>%n conexiones activas hacia la red Bitcoin</numerusform></translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk...</source>
+ <translation>Indexando bloques en disco...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk...</source>
+ <translation>Procesando bloques en disco...</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>
+ </message>
+ <message>
+ <source>%1 behind</source>
+ <translation>%1 atrás</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation>El último bloque recibido fue generado hace %1.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation>Las transacciones posteriores aún no están visibles.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Aviso</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Información</translation>
+ </message>
+ <message>
+ <source>Up to date</source>
+ <translation>Actualizado</translation>
+ </message>
+ <message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Mostrar el mensaje de ayuda %1 para obtener una lista de los posibles comandos de linea de comandos de Bitcoin</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>%1 cliente</translation>
+ </message>
+ <message>
+ <source>Catching up...</source>
+ <translation>Actualizando...</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation>Fecha: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Amount: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Tipo: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Etiqueta: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Dirección: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation>Transacción enviada</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation>Transacción entrante</translation>
+ </message>
+ <message>
+ <source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
+ <translation>El monedero está &lt;b&gt;cifrado&lt;/b&gt; y actualmente &lt;b&gt;desbloqueado&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>El monedero está &lt;b&gt;cifrado&lt;/b&gt; y actualmente &lt;b&gt;bloqueado&lt;/b&gt;</translation>
</message>
</context>
<context>
<name>CoinControlDialog</name>
- </context>
+ <message>
+ <source>Coin Selection</source>
+ <translation>Selección de la moneda</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation>Cantidad:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Bytes:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Cuantía:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Tasa:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Polvo:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Después de aplicar la comisión:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Cambio:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation>(des)marcar todos</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation>Modo árbol</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation>Modo lista</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Cantidad</translation>
+ </message>
+ <message>
+ <source>Received with label</source>
+ <translation>Recibido con etiqueta</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation>Recibido con dirección</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Fecha</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation>Confirmaciones</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Confirmado</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Copiar ubicación</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copiar ID de transacción</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Bloquear lo no gastado</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Desbloquear lo no gastado</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copiar cuota</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copiar después de couta</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copiar bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copiar polvo</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copiar cambio</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 bloqueado)</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>Esta etiqueta se vuelve roja si algún destinatario recibe una cantidad inferior a la actual puerta polvorienta.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Puede variar +/- %1 satoshi(s) por entrada.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sin etiqueta)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>cambia desde %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(cambio)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
+ <source>Edit Address</source>
+ <translation>Editar Dirección</translation>
+ </message>
+ <message>
<source>&amp;Label</source>
- <translation>Etiqueta</translation>
+ <translation>&amp;Etiqueta</translation>
+ </message>
+ <message>
+ <source>The label associated with this address list entry</source>
+ <translation>La etiqueta asociada con esta entrada de la lista de direcciones</translation>
+ </message>
+ <message>
+ <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
+ <translation>La dirección asociada con esta entrada de la lista de direcciones. Solo puede ser modificada para direcciones de envío.</translation>
</message>
<message>
<source>&amp;Address</source>
- <translation>Dirección</translation>
+ <translation>&amp;Dirección</translation>
+ </message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nueva dirección de recivimiento</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nueva dirección de envío</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Editar dirección de recivimiento</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Editar dirección de envío</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>La dirección introducida "%1" no es una dirección Bitcoin válida.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>La dirección introducida "%1" está ya en la agenda.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Podría no desbloquear el monedero.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Falló la generación de la nueva clave.</translation>
</message>
</context>
<context>
<name>FreespaceChecker</name>
- </context>
+ <message>
+ <source>A new data directory will be created.</source>
+ <translation>Se creará un nuevo directorio de datos.</translation>
+ </message>
+ <message>
+ <source>name</source>
+ <translation>nombre</translation>
+ </message>
+ <message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation>El directorio ya existe. Añada %1 si pretende crear aquí un directorio nuevo.</translation>
+ </message>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation>La ruta ya existe y no es un directorio.</translation>
+ </message>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation>No se puede crear un directorio de datos aquí.</translation>
+ </message>
+</context>
<context>
<name>HelpMessageDialog</name>
- </context>
+ <message>
+ <source>version</source>
+ <translation>versión</translation>
+ </message>
+ <message>
+ <source>(%1-bit)</source>
+ <translation>(%1-bit)</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation>Acerda de %1</translation>
+ </message>
+ <message>
+ <source>Command-line options</source>
+ <translation>Opciones de la línea de órdenes</translation>
+ </message>
+ <message>
+ <source>Usage:</source>
+ <translation>Uso:</translation>
+ </message>
+ <message>
+ <source>command-line options</source>
+ <translation>opciones de la consola de comandos</translation>
+ </message>
+ <message>
+ <source>UI Options:</source>
+ <translation>Opciones de interfaz de usuario:</translation>
+ </message>
+ <message>
+ <source>Choose data directory on startup (default: %u)</source>
+ <translation>Elegir directorio de datos al iniciar (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Set language, for example "de_DE" (default: system locale)</source>
+ <translation>Establecer el idioma, por ejemplo, "es_ES" (predeterminado: configuración regional del sistema)</translation>
+ </message>
+ <message>
+ <source>Start minimized</source>
+ <translation>Arrancar minimizado</translation>
+ </message>
+ <message>
+ <source>Set SSL root certificates for payment request (default: -system-)</source>
+ <translation>Establecer los certificados raíz SSL para solicitudes de pago (predeterminado: -system-)</translation>
+ </message>
+ <message>
+ <source>Show splash screen on startup (default: %u)</source>
+ <translation>Mostrar pantalla de bienvenida en el inicio (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Reiniciar todos los ajustes modificados en el GUI</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
+ <message>
+ <source>Welcome</source>
+ <translation>Bienvenido</translation>
+ </message>
+ <message>
+ <source>Welcome to %1.</source>
+ <translation>Bienvenido a %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>Al ser la primera vez que se ejecuta el programa, puede elegir donde %1 almacenara sus datos</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>%1 va a descargar y almacenar una copia de la cadena de bloques de Bitcoin. Al menos %2GB de datos seran almacenados en este directorio, que ira creciendo con el tiempo. El monedero se guardara tambien en ese directorio. </translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation>Utilizar el directorio de datos predeterminado</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation>Utilizar un directorio de datos personalizado:</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation>Error: no ha podido crearse el directorio de datos especificado "%1".</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n GB of free space available</source>
+ <translation><numerusform>%n GB de espacio libre</numerusform><numerusform>%n GB de espacio disponible</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation><numerusform>(de %n GB necesitados)</numerusform><numerusform>(de %n GB requeridos)</numerusform></translation>
+ </message>
+</context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Hora del último bloque</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Ocultar</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
- </context>
+ <message>
+ <source>Open URI</source>
+ <translation>Abrir URI...</translation>
+ </message>
+ <message>
+ <source>Open payment request from URI or file</source>
+ <translation>Abrir solicitud de pago a partir de un identificador URI o de un archivo</translation>
+ </message>
+ <message>
+ <source>URI:</source>
+ <translation>URI:</translation>
+ </message>
+ <message>
+ <source>Select payment request file</source>
+ <translation>Seleccionar archivo de sulicitud de pago</translation>
+ </message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Seleccionar el archivo de solicitud de pago para abrir</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
- </context>
+ <message>
+ <source>Options</source>
+ <translation>Opciones</translation>
+ </message>
+ <message>
+ <source>&amp;Main</source>
+ <translation>&amp;Principal</translation>
+ </message>
+ <message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>Iniciar automaticamente %1 al encender el sistema.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>&amp;Iniciar %1 al iniciar el sistema</translation>
+ </message>
+ <message>
+ <source>Size of &amp;database cache</source>
+ <translation>Tamaño de cache de la &amp;base de datos</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <translation>MB</translation>
+ </message>
+ <message>
+ <source>Number of script &amp;verification threads</source>
+ <translation>Número de hilos de &amp;verificación de scripts</translation>
+ </message>
+ <message>
+ <source>Accept connections from outside</source>
+ <translation>Aceptar conexiones desde el exterior</translation>
+ </message>
+ <message>
+ <source>Allow incoming connections</source>
+ <translation>Aceptar conexiones entrantes</translation>
+ </message>
+ <message>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation>Dirección IP del proxy (p. ej. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
+ </message>
+ <message>
+ <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
+ <translation>Minimizar en lugar de salir de la aplicación cuando la ventana está cerrada. Cuando se activa esta opción, la aplicación sólo se cerrará después de seleccionar Salir en el menú.</translation>
+ </message>
+ <message>
+ <source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
+ <translation>Identificadores URL de terceros (por ejemplo, un explorador de bloques) que aparecen en la pestaña de transacciones como elementos del menú contextual. El %s en la URL es reemplazado por el valor hash de la transacción. Se pueden separar URL múltiples por una barra vertical |.</translation>
+ </message>
+ <message>
+ <source>Third party transaction URLs</source>
+ <translation>Identificadores URL de transacciones de terceros</translation>
+ </message>
+ <message>
+ <source>Active command-line options that override above options:</source>
+ <translation>Opciones activas de consola de comandos que tienen preferencia sobre las opciones anteriores:</translation>
+ </message>
+ <message>
+ <source>Reset all client options to default.</source>
+ <translation>Restablecer todas las opciones predeterminadas del cliente.</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation>&amp;Restablecer opciones</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation>&amp;Red</translation>
+ </message>
+ <message>
+ <source>(0 = auto, &lt;0 = leave that many cores free)</source>
+ <translation>(0 = automático, &lt;0 = dejar libres ese número de núcleos)</translation>
+ </message>
+ <message>
+ <source>W&amp;allet</source>
+ <translation>&amp;Monedero</translation>
+ </message>
+ <message>
+ <source>Expert</source>
+ <translation>Experto</translation>
+ </message>
+ <message>
+ <source>Enable coin &amp;control features</source>
+ <translation>Habilitar funcionalidad de &amp;coin control</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>Si desactiva el gasto del cambio no confirmado, no se podrá usar el cambio de una transacción hasta que se alcance al menos una confirmación. Esto afecta también a cómo se calcula su saldo.</translation>
+ </message>
+ <message>
+ <source>&amp;Spend unconfirmed change</source>
+ <translation>&amp;Gastar cambio no confirmado</translation>
+ </message>
+ <message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
+ <translation>Abrir automáticamente el puerto del cliente Bitcoin en el router. Esta opción solo funciona si el router admite UPnP y está activado.</translation>
+ </message>
+ <message>
+ <source>Map port using &amp;UPnP</source>
+ <translation>Mapear el puerto mediante &amp;UPnP</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
+ <translation>Conectarse a la red Bitcoin a través de un proxy SOCKS5.</translation>
+ </message>
+ <message>
+ <source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
+ <translation>&amp;Conectarse a través de proxy SOCKS5 (proxy predeterminado):</translation>
+ </message>
+ <message>
+ <source>Proxy &amp;IP:</source>
+ <translation>Dirección &amp;IP del proxy:</translation>
+ </message>
+ <message>
+ <source>&amp;Port:</source>
+ <translation>&amp;Puerto:</translation>
+ </message>
+ <message>
+ <source>Port of the proxy (e.g. 9050)</source>
+ <translation>Puerto del servidor proxy (ej. 9050)</translation>
+ </message>
+ <message>
+ <source>Used for reaching peers via:</source>
+ <translation>Usado para alcanzar compañeros via:</translation>
+ </message>
+ <message>
+ <source>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
+ <translation>Muestra si el proxy SOCKS5 predeterminado es utilizado para llegar a los pares a traves de este tipo de red.</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>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source>
+ <translation>Conectar a la red Bitcoin mediante un proxy SOCKS5 por separado para los servicios ocultos de Tor.</translation>
+ </message>
+ <message>
+ <source>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</source>
+ <translation>Usar distintos proxys SOCKS5 para comunicarse vía Tor de forma anónima:</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation>&amp;Ventana</translation>
+ </message>
+ <message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>&amp;Ocultar el icono de la barra de tareas</translation>
+ </message>
+ <message>
+ <source>Hide tray icon</source>
+ <translation>Ocultar barra de tareas</translation>
+ </message>
+ <message>
+ <source>Show only a tray icon after minimizing the window.</source>
+ <translation>Minimizar la ventana a la bandeja de iconos del sistema.</translation>
+ </message>
+ <message>
+ <source>&amp;Minimize to the tray instead of the taskbar</source>
+ <translation>&amp;Minimizar a la bandeja en vez de a la barra de tareas</translation>
+ </message>
+ <message>
+ <source>M&amp;inimize on close</source>
+ <translation>M&amp;inimizar al cerrar</translation>
+ </message>
+ <message>
+ <source>&amp;Display</source>
+ <translation>&amp;Interfaz</translation>
+ </message>
+ <message>
+ <source>User Interface &amp;language:</source>
+ <translation>I&amp;dioma de la interfaz de usuario</translation>
+ </message>
+ <message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>El idioma de la interfaz de usuario puede establecerse aquí. Esta configuración tendrá efecto tras reiniciar %1.</translation>
+ </message>
+ <message>
+ <source>&amp;Unit to show amounts in:</source>
+ <translation>Mostrar las cantidades en la &amp;unidad:</translation>
+ </message>
+ <message>
+ <source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
+ <translation>Elegir la subdivisión predeterminada para mostrar cantidades en la interfaz y cuando se envían bitcoins.</translation>
+ </message>
+ <message>
+ <source>Whether to show coin control features or not.</source>
+ <translation>Mostrar o no funcionalidad de Coin Control</translation>
+ </message>
+ <message>
+ <source>&amp;OK</source>
+ <translation>&amp;Aceptar</translation>
+ </message>
+ <message>
+ <source>&amp;Cancel</source>
+ <translation>&amp;Cancelar</translation>
+ </message>
+ <message>
+ <source>default</source>
+ <translation>predeterminado</translation>
+ </message>
+ <message>
+ <source>none</source>
+ <translation>ninguna</translation>
+ </message>
+ <message>
+ <source>Confirm options reset</source>
+ <translation>Confirme el restablecimiento de las opciones</translation>
+ </message>
+ <message>
+ <source>Client restart required to activate changes.</source>
+ <translation>Se necesita reiniciar el cliente para activar los cambios.</translation>
+ </message>
+ <message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>El cliente se cerrará. ¿Desea continuar?</translation>
+ </message>
+ <message>
+ <source>This change would require a client restart.</source>
+ <translation>Este cambio exige el reinicio del cliente.</translation>
+ </message>
+ <message>
+ <source>The supplied proxy address is invalid.</source>
+ <translation>La dirección proxy indicada es inválida.</translation>
+ </message>
+</context>
<context>
<name>OverviewPage</name>
- </context>
+ <message>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </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>La información mostrada puede estar desactualizada. Su monedero se sincroniza automáticamente con la red Bitcoin después de que se haya establecido una conexión, pero este proceso aún no se ha completado.</translation>
+ </message>
+ <message>
+ <source>Watch-only:</source>
+ <translation>De observación:</translation>
+ </message>
+ <message>
+ <source>Available:</source>
+ <translation>Disponible:</translation>
+ </message>
+ <message>
+ <source>Your current spendable balance</source>
+ <translation>Su saldo disponible actual</translation>
+ </message>
+ <message>
+ <source>Pending:</source>
+ <translation>Pendiente:</translation>
+ </message>
+ <message>
+ <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
+ <translation>Total de transacciones pendientes de confirmar y que aún no contribuye al saldo disponible</translation>
+ </message>
+ <message>
+ <source>Immature:</source>
+ <translation>No madurado:</translation>
+ </message>
+ <message>
+ <source>Mined balance that has not yet matured</source>
+ <translation>Saldo recién minado que aún no ha madurado.</translation>
+ </message>
+ <message>
+ <source>Balances</source>
+ <translation>Saldos</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation>Total:</translation>
+ </message>
+ <message>
+ <source>Your current total balance</source>
+ <translation>Su saldo actual total</translation>
+ </message>
+ <message>
+ <source>Your current balance in watch-only addresses</source>
+ <translation>Su saldo actual en direcciones watch-only</translation>
+ </message>
+ <message>
+ <source>Spendable:</source>
+ <translation>Gastable:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation>Transacciones recientes</translation>
+ </message>
+ <message>
+ <source>Unconfirmed transactions to watch-only addresses</source>
+ <translation>Transacciones sin confirmar en direcciones watch-only</translation>
+ </message>
+ <message>
+ <source>Mined balance in watch-only addresses that has not yet matured</source>
+ <translation>Saldo minado en direcciones watch-only que aún no ha madurado</translation>
+ </message>
+ <message>
+ <source>Current total balance in watch-only addresses</source>
+ <translation>Saldo total en las direcciones watch-only</translation>
+ </message>
+</context>
+<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Fallo en la solicitud de pago</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>No se puede iniciar bitcoin: encargado click-para-pagar</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Manejo de URI</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>La búsqueda de solicitud de pago URL es válida: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Dirección de pago inválida %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 no puede ser analizado! Esto puede ser causado por una dirección Bitcoin inválida o parametros URI mal formados.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Manejo del archivo de solicitud de pago</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>¡El archivo de solicitud de pago no puede ser leído! Esto puede ser causado por un archivo de solicitud de pago inválido.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Solicitud de pago rechazada</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>La red de solicitud de pago no cimbina la red cliente.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Solicitud de pago caducada.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>La solicitud de pago no se ha iniciado.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Solicitudes de pago sin verificar a scripts de pago habitual no se soportan.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Solicitud de pago inválida.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Cantidad de pago solicitada de %1 es demasiado pequeña (considerado polvo).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Reembolsar desde %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>Solicitud de pago de %1 es demasiado grande (%2 bytes, permitidos %3 bytes).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Fallo al comunicar con %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>¡La solicitud de pago no puede ser analizada!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Mala respuesta desde el servidor %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Fallo de solicitud de red</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Pago declarado</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
+ <message>
+ <source>User Agent</source>
+ <translation>User Agent</translation>
+ </message>
+ <message>
+ <source>Node/Service</source>
+ <translation>Nodo/Servicio</translation>
+ </message>
</context>
<context>
<name>QObject</name>
+ <message>
+ <source>Amount</source>
+ <translation>Cantidad</translation>
+ </message>
+ <message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation>Introducir una dirección Bitcoin (p. ej. %1)</translation>
+ </message>
+ <message>
+ <source>%1 d</source>
+ <translation>%1 d</translation>
+ </message>
+ <message>
+ <source>%1 h</source>
+ <translation>%1 h</translation>
+ </message>
+ <message>
+ <source>%1 m</source>
+ <translation>%1 m</translation>
+ </message>
+ <message>
+ <source>%1 s</source>
+ <translation>%1 s</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Ninguno</translation>
+ </message>
+ <message>
+ <source>N/A</source>
+ <translation>N/D</translation>
+ </message>
+ <message>
+ <source>%1 ms</source>
+ <translation>%1 ms</translation>
+ </message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 y %2</translation>
+ </message>
</context>
<context>
- <name>RPCConsole</name>
+ <name>QObject::QObject</name>
</context>
<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Guardar imagen...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Copiar imagen</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Guardar código QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Imagen PNG (*.png)</translation>
+ </message>
+</context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>N/A</source>
+ <translation>N/D</translation>
+ </message>
+ <message>
+ <source>Client version</source>
+ <translation>Versión del cliente</translation>
+ </message>
+ <message>
+ <source>&amp;Information</source>
+ <translation>&amp;Información</translation>
+ </message>
+ <message>
+ <source>Debug window</source>
+ <translation>Ventana de depuración</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <translation>General</translation>
+ </message>
+ <message>
+ <source>Using BerkeleyDB version</source>
+ <translation>Utilizando la versión de BerkeleyDB</translation>
+ </message>
+ <message>
+ <source>Datadir</source>
+ <translation>Datadir</translation>
+ </message>
+ <message>
+ <source>Startup time</source>
+ <translation>Hora de inicio</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Red</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <source>Number of connections</source>
+ <translation>Número de conexiones</translation>
+ </message>
+ <message>
+ <source>Block chain</source>
+ <translation>Cadena de bloques</translation>
+ </message>
+ <message>
+ <source>Current number of blocks</source>
+ <translation>Número actual de bloques</translation>
+ </message>
+ <message>
+ <source>Memory Pool</source>
+ <translation>Piscina de Memoria</translation>
+ </message>
+ <message>
+ <source>Current number of transactions</source>
+ <translation>Número actual de transacciones</translation>
+ </message>
+ <message>
+ <source>Memory usage</source>
+ <translation>Uso de memoria</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation>Recibido</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation>Enviado</translation>
+ </message>
+ <message>
+ <source>&amp;Peers</source>
+ <translation>&amp;Pares</translation>
+ </message>
+ <message>
+ <source>Banned peers</source>
+ <translation>Peers Bloqueados</translation>
+ </message>
+ <message>
+ <source>Select a peer to view detailed information.</source>
+ <translation>Seleccionar un par para ver su información detallada.</translation>
+ </message>
+ <message>
+ <source>Whitelisted</source>
+ <translation>En la lista blanca</translation>
+ </message>
+ <message>
+ <source>Direction</source>
+ <translation>Dirección</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation>Versión</translation>
+ </message>
+ <message>
+ <source>Starting Block</source>
+ <translation>Importando bloques...</translation>
+ </message>
+ <message>
+ <source>Synced Headers</source>
+ <translation>Sincronizar Cabeceras</translation>
+ </message>
+ <message>
+ <source>Synced Blocks</source>
+ <translation>Bloques Sincronizados</translation>
+ </message>
+ <message>
+ <source>User Agent</source>
+ <translation>User Agent</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 el archivo de depuración %1 desde el directorio de datos actual. Puede tardar unos segundos para ficheros de gran tamaño.</translation>
+ </message>
+ <message>
+ <source>Decrease font size</source>
+ <translation>Disminuir tamaño de letra</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation>Aumentar tamaño de letra</translation>
+ </message>
+ <message>
+ <source>Services</source>
+ <translation>Servicios</translation>
+ </message>
+ <message>
+ <source>Ban Score</source>
+ <translation>Puntuación de bloqueo</translation>
+ </message>
+ <message>
+ <source>Connection Time</source>
+ <translation>Duración de la conexión</translation>
+ </message>
+ <message>
+ <source>Last Send</source>
+ <translation>Ultimo envío</translation>
+ </message>
+ <message>
+ <source>Last Receive</source>
+ <translation>Ultima recepción</translation>
+ </message>
+ <message>
+ <source>Ping Time</source>
+ <translation>Ping</translation>
+ </message>
+ <message>
+ <source>The duration of a currently outstanding ping.</source>
+ <translation>La duración de un ping actualmente en proceso.</translation>
+ </message>
+ <message>
+ <source>Ping Wait</source>
+ <translation>Espera de Ping</translation>
+ </message>
+ <message>
+ <source>Time Offset</source>
+ <translation>Desplazamiento de tiempo</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Hora del último bloque</translation>
+ </message>
+ <message>
+ <source>&amp;Open</source>
+ <translation>&amp;Abrir</translation>
+ </message>
+ <message>
+ <source>&amp;Console</source>
+ <translation>&amp;Consola</translation>
+ </message>
+ <message>
+ <source>&amp;Network Traffic</source>
+ <translation>&amp;Tráfico de Red</translation>
+ </message>
+ <message>
+ <source>&amp;Clear</source>
+ <translation>&amp;Vaciar</translation>
+ </message>
+ <message>
+ <source>Totals</source>
+ <translation>Total:</translation>
+ </message>
+ <message>
+ <source>In:</source>
+ <translation>Entrante:</translation>
+ </message>
+ <message>
+ <source>Out:</source>
+ <translation>Saliente:</translation>
+ </message>
+ <message>
+ <source>Debug log file</source>
+ <translation>Archivo de registro de depuración</translation>
+ </message>
+ <message>
+ <source>Clear console</source>
+ <translation>Borrar consola</translation>
+ </message>
+ <message>
+ <source>1 &amp;hour</source>
+ <translation>1 &amp;hora</translation>
+ </message>
+ <message>
+ <source>1 &amp;day</source>
+ <translation>1 &amp;día</translation>
+ </message>
+ <message>
+ <source>1 &amp;week</source>
+ <translation>1 &amp;semana</translation>
+ </message>
+ <message>
+ <source>1 &amp;year</source>
+ <translation>1 &amp;año</translation>
+ </message>
+ <message>
+ <source>Welcome to the %1 RPC console.</source>
+ <translation>Bienvenido a la consola 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>Use las flechas arriba y abajo para navegar por el historial y &lt;b&gt;Control+L&lt;/b&gt; para vaciar la pantalla.</translation>
+ </message>
+ <message>
+ <source>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</source>
+ <translation>Escriba &lt;b&gt;help&lt;/b&gt; para ver un resumen de los comandos disponibles.</translation>
+ </message>
+ <message>
+ <source>%1 B</source>
+ <translation>%1 B</translation>
+ </message>
+ <message>
+ <source>%1 KB</source>
+ <translation>%1 KB</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <translation>%1 MB</translation>
+ </message>
+ <message>
+ <source>%1 GB</source>
+ <translation>%1 GB</translation>
+ </message>
+ <message>
+ <source>(node id: %1)</source>
+ <translation>(nodo: %1)</translation>
+ </message>
+ <message>
+ <source>via %1</source>
+ <translation>via %1</translation>
+ </message>
+ <message>
+ <source>never</source>
+ <translation>nunca</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <translation>Entrante</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <translation>Saliente</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sí</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation>Desconocido</translation>
+ </message>
+</context>
+<context>
<name>ReceiveCoinsDialog</name>
- </context>
+ <message>
+ <source>&amp;Amount:</source>
+ <translation>Cantidad</translation>
+ </message>
+ <message>
+ <source>&amp;Label:</source>
+ <translation>&amp;Etiqueta:</translation>
+ </message>
+ <message>
+ <source>&amp;Message:</source>
+ <translation>Mensaje:</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>
+ <translation>Reutilizar una de las direcciones previamente usadas para recibir. Reutilizar direcciones tiene problemas de seguridad y privacidad. No lo uses a menos que antes regeneres una solicitud de pago.</translation>
+ </message>
+ <message>
+ <source>R&amp;euse an existing receiving address (not recommended)</source>
+ <translation>R&amp;eutilizar una dirección existente para recibir (no recomendado)</translation>
+ </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>Un mensaje opcional para adjuntar a la solicitud de pago, que se muestra cuando se abre la solicitud. Nota: El mensaje no se enviará con el pago por la red Bitcoin.</translation>
+ </message>
+ <message>
+ <source>An optional label to associate with the new receiving address.</source>
+ <translation>Etiqueta opcional para asociar con la nueva dirección de recepción.</translation>
+ </message>
+ <message>
+ <source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
+ <translation>Utilice este formulario para solicitar pagos. Todos los campos son &lt;b&gt;opcionales&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
+ <translation>Para solicitar una cantidad opcional. Deje este vacío o cero para no solicitar una cantidad específica.</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation>Vaciar todos los campos del formulario.</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Vaciar</translation>
+ </message>
+ <message>
+ <source>Requested payments history</source>
+ <translation>Historial de pagos solicitados</translation>
+ </message>
+ <message>
+ <source>&amp;Request payment</source>
+ <translation>&amp;Solicitar pago</translation>
+ </message>
+ <message>
+ <source>Show the selected request (does the same as double clicking an entry)</source>
+ <translation>Muestra la petición seleccionada (También doble clic)</translation>
+ </message>
+ <message>
+ <source>Show</source>
+ <translation>Mostrar</translation>
+ </message>
+ <message>
+ <source>Remove the selected entries from the list</source>
+ <translation>Borrar de la lista las direcciónes actualmente seleccionadas</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation>Eliminar</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar capa</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Copiar imagen</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>QR Code</source>
+ <translation>Código QR</translation>
+ </message>
+ <message>
+ <source>Copy &amp;URI</source>
+ <translation>Copiar &amp;URI</translation>
+ </message>
+ <message>
<source>Copy &amp;Address</source>
- <translation>&amp;Copiar Direccón</translation>
+ <translation>Copiar &amp;Dirección</translation>
</message>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>Guardar Imagen...</translation>
+ </message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Solicitar pago a %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Información de pago</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Dirección</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Cantidad</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mensaje</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>URI resultante demasiado grande, trate de reducir el texto de etiqueta / mensaje.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Fallo al codificar URI en código QR.</translation>
+ </message>
+</context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Fecha</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mensaje</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sin etiqueta)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(no hay mensaje)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(no hay solicitud de cantidad)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Solicitado</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
- </context>
+ <message>
+ <source>Send Coins</source>
+ <translation>Enviar bitcoins</translation>
+ </message>
+ <message>
+ <source>Coin Control Features</source>
+ <translation>Características de Coin Control</translation>
+ </message>
+ <message>
+ <source>Inputs...</source>
+ <translation>Entradas...</translation>
+ </message>
+ <message>
+ <source>automatically selected</source>
+ <translation>Seleccionado automáticamente</translation>
+ </message>
+ <message>
+ <source>Insufficient funds!</source>
+ <translation>Fondos insuficientes!</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation>Cantidad:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Bytes:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Cuantía:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Tasa:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Después de tasas:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Cambio:</translation>
+ </message>
+ <message>
+ <source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
+ <translation>Si se marca esta opción pero la dirección de cambio está vacía o es inválida, el cambio se enviará a una nueva dirección recién generada.</translation>
+ </message>
+ <message>
+ <source>Custom change address</source>
+ <translation>Dirección propia</translation>
+ </message>
+ <message>
+ <source>Transaction Fee:</source>
+ <translation>Comisión de Transacción:</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Elija...</translation>
+ </message>
+ <message>
+ <source>collapse fee-settings</source>
+ <translation>Colapsar ajustes de cuota</translation>
+ </message>
+ <message>
+ <source>per kilobyte</source>
+ <translation>por kilobyte</translation>
+ </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>Si la tarifa de aduana se establece en 1000 satoshis y la transacción está a sólo 250 bytes, entonces "por kilobyte" sólo paga 250 satoshis de cuota, mientras que "el mínimo total" pagaría 1.000 satoshis. Para las transacciones más grandes que un kilobyte ambos pagan por kilobyte</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Ocultar</translation>
+ </message>
+ <message>
+ <source>total at least</source>
+ <translation>total por lo menos</translation>
+ </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>Pagando solamente la cuota mínima es correcto, siempre y cuando haya menos volumen de transacciones que el espacio en los bloques. Pero tenga en cuenta que esto puede terminar en una transacción nunca confirmada, una vez que haya más demanda para transacciones Bitcoin que la red pueda procesar.</translation>
+ </message>
+ <message>
+ <source>(read the tooltip)</source>
+ <translation>(leer la sugerencia)</translation>
+ </message>
+ <message>
+ <source>Recommended:</source>
+ <translation>Recomendado:</translation>
+ </message>
+ <message>
+ <source>Custom:</source>
+ <translation>Personalizado:</translation>
+ </message>
+ <message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
+ <translation>(Tarifa inteligente no inicializado aún. Esto generalmente lleva a pocos bloques...)</translation>
+ </message>
+ <message>
+ <source>normal</source>
+ <translation>normal</translation>
+ </message>
+ <message>
+ <source>fast</source>
+ <translation>rápido</translation>
+ </message>
+ <message>
+ <source>Send to multiple recipients at once</source>
+ <translation>Enviar a múltiples destinatarios de una vez</translation>
+ </message>
+ <message>
+ <source>Add &amp;Recipient</source>
+ <translation>Añadir &amp;destinatario</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation>Vaciar todos los campos del formulario</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Polvo:</translation>
+ </message>
+ <message>
+ <source>Clear &amp;All</source>
+ <translation>Vaciar &amp;todo</translation>
+ </message>
+ <message>
+ <source>Balance:</source>
+ <translation>Saldo:</translation>
+ </message>
+ <message>
+ <source>Confirm the send action</source>
+ <translation>Confirmar el envío</translation>
+ </message>
+ <message>
+ <source>S&amp;end</source>
+ <translation>&amp;Enviar</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copiar cuota</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copiar después de couta</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copiar bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copiar polvo</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copiar cambio</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>¿Seguro que quiere enviar?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>añadido como transacción de cuota</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Cantidad total %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>o</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Confirmar enviar monedas</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>La dirección de destinatario no es válida. Por favor revísela.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>La cantidad a pagar debe de ser mayor que 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>La cantidad excede su saldo.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>El total excede su saldo cuando la cuota de transacción de %1 es incluida.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Dirección duplicada encontrada: la dirección sólo debería ser utilizada una vez por cada uso.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>¡Falló la creación de transacción!</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Una couta mayor que %1 se considera una cuota irracionalmente alta.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Solicitud de pago caducada.</translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Pagar únicamente la cuota solicitada de %1</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Alerta: dirección Bitcoin inválida</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Alerta: dirección cambiada desconocida</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sin etiqueta)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
- </context>
+ <message>
+ <source>A&amp;mount:</source>
+ <translation>Ca&amp;ntidad:</translation>
+ </message>
+ <message>
+ <source>Pay &amp;To:</source>
+ <translation>&amp;Pagar a:</translation>
+ </message>
+ <message>
+ <source>&amp;Label:</source>
+ <translation>&amp;Etiqueta:</translation>
+ </message>
+ <message>
+ <source>Choose previously used address</source>
+ <translation>Escoger direcciones previamente usadas</translation>
+ </message>
+ <message>
+ <source>This is a normal payment.</source>
+ <translation>Esto es un pago ordinario.</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to send the payment to</source>
+ <translation>Dirección Bitcoin a la que enviar el pago</translation>
+ </message>
+ <message>
+ <source>Alt+A</source>
+ <translation>Alt+A</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation>Pegar dirección desde portapapeles</translation>
+ </message>
+ <message>
+ <source>Alt+P</source>
+ <translation>Alt+P</translation>
+ </message>
+ <message>
+ <source>Remove this entry</source>
+ <translation>Eliminar esta transacción</translation>
+ </message>
+ <message>
+ <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
+ <translation>La cuota será deducida de la cantidad que sea mandada. El destinatario recibirá menos bitcoins de los que entres en el </translation>
+ </message>
+ <message>
+ <source>S&amp;ubtract fee from amount</source>
+ <translation>Restar comisiones a la cantidad</translation>
+ </message>
+ <message>
+ <source>Message:</source>
+ <translation>Mensaje:</translation>
+ </message>
+ <message>
+ <source>This is an unauthenticated payment request.</source>
+ <translation>Esta es una petición de pago no autentificada.</translation>
+ </message>
+ <message>
+ <source>This is an authenticated payment request.</source>
+ <translation>Esta es una petición de pago autentificada.</translation>
+ </message>
+ <message>
+ <source>Enter a label for this address to add it to the list of used addresses</source>
+ <translation>Introduce una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas</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>Un mensaje que se adjuntó a la bitcoin: URL que será almacenada con la transacción para su referencia. Nota: Este mensaje no se envía a través de la red Bitcoin.</translation>
+ </message>
+ <message>
+ <source>Pay To:</source>
+ <translation>Paga a:</translation>
+ </message>
+ <message>
+ <source>Memo:</source>
+ <translation>Memo:</translation>
+ </message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Introduzca una etiqueta para esta dirección para añadirla a su agenda</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Sí</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
- </context>
+ <message>
+ <source>%1 is shutting down...</source>
+ <translation>%1 se esta cerrando...</translation>
+ </message>
+ <message>
+ <source>Do not shut down the computer until this window disappears.</source>
+ <translation>No apague el equipo hasta que desaparezca esta ventana.</translation>
+ </message>
+</context>
<context>
<name>SignVerifyMessageDialog</name>
- </context>
+ <message>
+ <source>Signatures - Sign / Verify a Message</source>
+ <translation>Firmas - Firmar / verificar un mensaje</translation>
+ </message>
+ <message>
+ <source>&amp;Sign Message</source>
+ <translation>&amp;Firmar mensaje</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>Puede firmar los mensajes con sus direcciones para demostrar que las posee. Tenga cuidado de no firmar cualquier cosa de manera vaga o aleatoria, pues los ataques de phishing pueden tratar de engañarle firmando su identidad a través de ellos. Sólo firme declaraciones totalmente detalladas con las que usted esté de acuerdo.</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to sign the message with</source>
+ <translation>Dirección Bitcoin con la que firmar el mensaje</translation>
+ </message>
+ <message>
+ <source>Choose previously used address</source>
+ <translation>Escoger dirección previamente usada</translation>
+ </message>
+ <message>
+ <source>Alt+A</source>
+ <translation>Alt+A</translation>
+ </message>
+ <message>
+ <source>Paste address from clipboard</source>
+ <translation>Pegar dirección desde portapapeles</translation>
+ </message>
+ <message>
+ <source>Alt+P</source>
+ <translation>Alt+P</translation>
+ </message>
+ <message>
+ <source>Enter the message you want to sign here</source>
+ <translation>Introduzca el mensaje que desea firmar aquí</translation>
+ </message>
+ <message>
+ <source>Signature</source>
+ <translation>Firma</translation>
+ </message>
+ <message>
+ <source>Copy the current signature to the system clipboard</source>
+ <translation>Copiar la firma actual al portapapeles del sistema</translation>
+ </message>
+ <message>
+ <source>Sign the message to prove you own this Bitcoin address</source>
+ <translation>Firmar el mensaje para demostrar que se posee esta dirección Bitcoin</translation>
+ </message>
+ <message>
+ <source>Sign &amp;Message</source>
+ <translation>Firmar &amp;mensaje</translation>
+ </message>
+ <message>
+ <source>Reset all sign message fields</source>
+ <translation>Vaciar todos los campos de la firma de mensaje</translation>
+ </message>
+ <message>
+ <source>Clear &amp;All</source>
+ <translation>Vaciar &amp;todo</translation>
+ </message>
+ <message>
+ <source>&amp;Verify Message</source>
+ <translation>&amp;Verificar mensaje</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>Introduzca la dirección para la firma, el mensaje (asegurándose de copiar tal cual los saltos de línea, espacios, tabulaciones, etc.) y la firma a continuación para verificar el mensaje. Tenga cuidado de no asumir más información de lo que dice el propio mensaje firmado para evitar fraudes basados en ataques de tipo man-in-the-middle. </translation>
+ </message>
+ <message>
+ <source>The Bitcoin address the message was signed with</source>
+ <translation>La dirección Bitcoin con la que se firmó el mensaje</translation>
+ </message>
+ <message>
+ <source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
+ <translation>Verificar el mensaje para comprobar que fue firmado con la dirección Bitcoin indicada</translation>
+ </message>
+ <message>
+ <source>Verify &amp;Message</source>
+ <translation>Verificar &amp;mensaje</translation>
+ </message>
+ <message>
+ <source>Reset all verify message fields</source>
+ <translation>Vaciar todos los campos de la verificación de mensaje</translation>
+ </message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Click en "Fírmar mensaje" para generar una firma</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>La dirección introducida no es válida.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Por favor revise la dirección e inténtelo de nuevo.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>La dirección introducida no remite a una clave.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>El desbloqueo del monedero fue cancelado.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>La clave privada de la dirección introducida no está disponible.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Falló la firma del mensaje.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Mensaje firmado.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>La firma no pudo descodificarse.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Por favor compruebe la firma y pruebe de nuevo.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>La firma no se combinó con el mensaje.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Falló la verificación del mensaje.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Mensaje verificado.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
- </context>
+ <message>
+ <source>[testnet]</source>
+ <translation>[testnet]</translation>
+ </message>
+</context>
<context>
<name>TrafficGraphWidget</name>
- </context>
+ <message>
+ <source>KB/s</source>
+ <translation>KB/s</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Open until %1</source>
+ <translation>Abierto hasta %1</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>Hay un conflicto con la traducción de las confirmaciones %1</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/sin conexión</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/no confirmado, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>en el equipo de memoria</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>no en el equipo de memoria</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>abandonado</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/no confirmado</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>confirmaciones %1</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Estado</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, no ha sido emitido con éxito aún</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Fecha</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Fuente</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Generado</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Desde</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconocido</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Para</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>dirección propia</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>de observación</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etiqueta</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Credito</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>no aceptada</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Enviado</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Total enviado</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Total recibido</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Comisión de transacción</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Cantidad neta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mensaje</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Comentario</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>Identificador de transacción (ID)</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Indice de salida</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Vendedor</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>Los bitcoins generados deben madurar %1 bloques antes de que puedan gastarse. Cuando generó este bloque, se transmitió a la red para que se añadiera a la cadena de bloques. Si no consigue entrar en la cadena, su estado cambiará a "no aceptado" y ya no se podrá gastar. Esto puede ocurrir ocasionalmente si otro nodo genera un bloque a pocos segundos del suyo.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Información de depuración</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transacción</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>entradas</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Cantidad</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>verdadero</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>falso</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
- </context>
+ <message>
+ <source>This pane shows a detailed description of the transaction</source>
+ <translation>Esta ventana muestra información detallada sobre la transacción</translation>
+ </message>
+ <message>
+ <source>Details for %1</source>
+ <translation>Detalles para %1</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Fecha</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>Abierto hasta %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Sin conexion</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Sin confirmar</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Abandonado</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Confirmando (%1 de %2 confirmaciones recomendadas)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Confirmado (%1 confirmaciones)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>En conflicto</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>No disponible (%1 confirmaciones. Estarán disponibles al cabo de %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Este bloque no ha sido recibido por otros nodos y probablemente no sea aceptado!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Generado pero no aceptado</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Recibido con</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Recibidos de</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviado a</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Pago proprio</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minado</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>de observación</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(nd)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sin etiqueta)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Estado de transacción. Pasa el ratón sobre este campo para ver el número de confirmaciones.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Fecha y hora en que se recibió la transacción.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Tipo de transacción.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Si una dirección watch-only está involucrada en esta transacción o no.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Descripción de la transacción definido por el usuario.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Cantidad retirada o añadida al saldo.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Todo</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Hoy</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Esta semana</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Este mes</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Mes pasado</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Este año</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Rango...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Recibido con</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviado a</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>A usted mismo</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minado</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Otra</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Introduzca una dirección o etiqueta que buscar</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Cantidad mínima</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Transacción abandonada</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Copiar ubicación</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar capa</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar cantidad</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copiar ID de transacción</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Copiar transacción raw</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Copiar todos los detalles de la transacción</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Editar etiqueta</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Mostrar detalles de la transacción</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exportar historial de transacciones</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Archivo separado de coma (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Confirmado</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>De observación</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Fecha</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipo</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Dirección</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Falló la exportación</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Ha habido un error al intentar guardar la transacción con %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Exportación finalizada</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>La transacción ha sido guardada en %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Rango:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>para</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
- </context>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation>Unidad en la que se muestran las cantidades. Haga clic para seleccionar otra unidad.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>No se ha cargado ningún monedero</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Enviar</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 a un archivo los datos de esta pestaña</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Copia de seguridad del monedero</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Datos de monedero (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>La copia de seguridad ha fallado</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Ha habido un error al intentar guardar los datos del monedero en %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Se ha completado con éxito la copia de respaldo</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Los datos del monedero se han guardado con éxito en %1.</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
- </context>
+ <message>
+ <source>Options:</source>
+ <translation>Opciones:
+</translation>
+ </message>
+ <message>
+ <source>Specify data directory</source>
+ <translation>Especificar directorio para los datos</translation>
+ </message>
+ <message>
+ <source>Connect to a node to retrieve peer addresses, and disconnect</source>
+ <translation>Conectar a un nodo para obtener direcciones de pares y desconectar</translation>
+ </message>
+ <message>
+ <source>Specify your own public address</source>
+ <translation>Especifique su propia dirección pública</translation>
+ </message>
+ <message>
+ <source>Accept command line and JSON-RPC commands</source>
+ <translation>Aceptar comandos consola y JSON-RPC
+</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>
+ <message>
+ <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
+ <translation>La Poda se ha configurado por debajo del minimo de %d MiB. Por favor utiliza un valor mas alto.</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>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>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>
+ <message>
+ <source>Error: A fatal internal error occurred, see debug.log for details</source>
+ <translation>Un error interno fatal ocurrió, ver debug.log para detalles</translation>
+ </message>
+ <message>
+ <source>Fee (in %s/kB) to add to transactions you send (default: %s)</source>
+ <translation>Comisión (en %s/KB) para agregar a las transacciones que envíe (por defecto: %s)</translation>
+ </message>
+ <message>
+ <source>Pruning blockstore...</source>
+ <translation>Poda blockstore ...</translation>
+ </message>
+ <message>
+ <source>Run in the background as a daemon and accept commands</source>
+ <translation>Ejecutar en segundo plano como daemon y aceptar comandos
+</translation>
+ </message>
+ <message>
+ <source>Unable to start HTTP server. See debug log for details.</source>
+ <translation>No se ha podido comenzar el servidor HTTP. Ver debug log para detalles.</translation>
+ </message>
+ <message>
+ <source>Bitcoin Core</source>
+ <translation>Bitcoin Core</translation>
+ </message>
+ <message>
+ <source>The %s developers</source>
+ <translation>Los %s desarrolladores</translation>
+ </message>
+ <message>
+ <source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
+ <translation>Una comision (en %s/kB) que sera usada cuando las estimacion de comision no disponga de suficientes datos (predeterminado: %s)</translation>
+ </message>
+ <message>
+ <source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
+ <translation>Aceptar transacciones retransmitidas recibidas desde nodos en la lista blanca incluso cuando no estés retransmitiendo transacciones (predeterminado: %d)</translation>
+ </message>
+ <message>
+ <source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
+ <translation>Vincular a la dirección dada y escuchar siempre en ella. Utilice la notación [host]:port para IPv6</translation>
+ </message>
+ <message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation>No se puede bloquear el directorio %s. %s ya se está ejecutando.</translation>
+ </message>
+ <message>
+ <source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
+ <translation>Borrar todas las transacciones del monedero y sólo recuperar aquellas partes de la cadena de bloques por medio de -rescan on startup.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
+ <translation>Error cargando %s: No puede habilitar HD en un monedero existente que no es HD</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>Error leyendo %s!. Todas las claves se han leido correctamente, pero los datos de transacciones o la libreta de direcciones pueden faltar o ser incorrectos.</translation>
+ </message>
+ <message>
+ <source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
+ <translation>Ejecutar comando cuando una transacción del monedero cambia (%s en cmd se remplazará por TxID)</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>
+ <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>Máximas comisiones totales (en %s) para utilizar en una sola transacción de la cartera; establecer esto demasiado bajo puede abortar grandes transacciones (predeterminado: %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>
+ <translation>Por favor, compruebe si la fecha y hora en su computadora son correctas! Si su reloj esta mal, %s no trabajara correctamente. </translation>
+ </message>
+ <message>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
+ <translation>Contribuya si encuentra %s de utilidad. Visite %s para mas información acerca del programa.</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>
+ <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>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>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>
+ <message>
+ <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
+ <translation>Utiliza UPnP para asignar el puerto de escucha (predeterminado: 1 cuando esta escuchando sin -proxy)</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>
+ <message>
+ <source>%s corrupt, salvage failed</source>
+ <translation>%s corrupto. Fracasó la recuperacion</translation>
+ </message>
+ <message>
+ <source>-maxmempool must be at least %d MB</source>
+ <translation>-maxmempool debe ser por lo menos de %d MB</translation>
+ </message>
+ <message>
+ <source>&lt;category&gt; can be:</source>
+ <translation>&lt;category&gt; puede ser:</translation>
+ </message>
+ <message>
+ <source>Append comment to the user agent string</source>
+ <translation>Adjunta un comentario a la linea de agente de usuario</translation>
+ </message>
+ <message>
+ <source>Attempt to recover private keys from a corrupt wallet on startup</source>
+ <translation>Intento de recuperar claves privadas de un monedero corrupto en arranque</translation>
+ </message>
+ <message>
+ <source>Block creation options:</source>
+ <translation>Opciones de creación de bloques:</translation>
+ </message>
+ <message>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>No se puede resolver -%s direccion: '%s'</translation>
+ </message>
+ <message>
+ <source>Change index out of range</source>
+ <translation>Cambio de indice fuera de rango</translation>
+ </message>
+ <message>
+ <source>Connection options:</source>
+ <translation>Opciones de conexión:</translation>
+ </message>
+ <message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Copyright (C) %i-%i</translation>
+ </message>
+ <message>
+ <source>Corrupted block database detected</source>
+ <translation>Corrupción de base de datos de bloques detectada.</translation>
+ </message>
+ <message>
+ <source>Debugging/Testing options:</source>
+ <translation>Opciones de depuración/pruebas:</translation>
+ </message>
+ <message>
+ <source>Do not load the wallet and disable wallet RPC calls</source>
+ <translation>No cargar el monedero y desactivar las llamadas RPC del monedero</translation>
+ </message>
+ <message>
+ <source>Do you want to rebuild the block database now?</source>
+ <translation>¿Quieres reconstruir la base de datos de bloques ahora?</translation>
+ </message>
+ <message>
+ <source>Enable publish hash block in &lt;address&gt;</source>
+ <translation>Activar publicar bloque .hash en &lt;.Address&gt;</translation>
+ </message>
+ <message>
+ <source>Enable publish hash transaction in &lt;address&gt;</source>
+ <translation>Activar publicar transacción .hash en &lt;.Address&gt;</translation>
+ </message>
+ <message>
+ <source>Enable publish raw block in &lt;address&gt;</source>
+ <translation>Habilita la publicacion de bloques en bruto en &lt;direccion&gt;</translation>
+ </message>
+ <message>
+ <source>Enable publish raw transaction in &lt;address&gt;</source>
+ <translation>Habilitar publicar transacción en rama en &lt;dirección&gt;</translation>
+ </message>
+ <message>
+ <source>Enable transaction replacement in the memory pool (default: %u)</source>
+ <translation>Habilita el reemplazamiento de transacciones en la piscina de memoria (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Error initializing block database</source>
+ <translation>Error al inicializar la base de datos de bloques</translation>
+ </message>
+ <message>
+ <source>Error initializing wallet database environment %s!</source>
+ <translation>Error al inicializar el entorno de la base de datos del monedero %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s</source>
+ <translation>Error cargando %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation>Error cargando %s: Monedero dañado</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation>Error cargando %s: Monedero requiere un versión mas reciente de %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: You can't disable HD on a already existing HD wallet</source>
+ <translation>Error cargando %s: No puede deshabilitar HD en un monedero existente que ya es HD</translation>
+ </message>
+ <message>
+ <source>Error loading block database</source>
+ <translation>Error cargando base de datos de bloques</translation>
+ </message>
+ <message>
+ <source>Error opening block database</source>
+ <translation>Error al abrir base de datos de bloques.</translation>
+ </message>
+ <message>
+ <source>Error: Disk space is low!</source>
+ <translation>Error: ¡Espacio en disco bajo!</translation>
+ </message>
+ <message>
+ <source>Failed to listen on any port. Use -listen=0 if you want this.</source>
+ <translation>Ha fallado la escucha en todos los puertos. Use -listen=0 si desea esto.</translation>
+ </message>
+ <message>
+ <source>Importing...</source>
+ <translation>Importando...</translation>
+ </message>
+ <message>
+ <source>Incorrect or no genesis block found. Wrong datadir for network?</source>
+ <translation>Incorrecto o bloque de génesis no encontrado. Datadir equivocada para la red?</translation>
+ </message>
+ <message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation>La inicialización de la verificación de validez falló. Se está apagando %s.</translation>
+ </message>
+ <message>
+ <source>Invalid -onion address: '%s'</source>
+ <translation>Dirección -onion inválida: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
+ <translation>Cantidad no valida para -%s=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
+ <translation>Cantidad inválida para -fallbackfee=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
+ <source>Keep the transaction memory pool below &lt;n&gt; megabytes (default: %u)</source>
+ <translation>Mantener la memoria de transacciones por debajo de &lt;n&gt; megabytes (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Loading banlist...</source>
+ <translation>Cargando banlist...</translation>
+ </message>
+ <message>
+ <source>Location of the auth cookie (default: data dir)</source>
+ <translation>Ubicación de la cookie de autenticación (default: data dir)</translation>
+ </message>
+ <message>
+ <source>Not enough file descriptors available.</source>
+ <translation>No hay suficientes descriptores de archivo disponibles. </translation>
+ </message>
+ <message>
+ <source>Only connect to nodes in network &lt;net&gt; (ipv4, ipv6 or onion)</source>
+ <translation>Sólo conectar a nodos en redes &lt;net&gt; (ipv4, ipv6 o onion)</translation>
+ </message>
+ <message>
+ <source>Print this help message and exit</source>
+ <translation>Imprimir este mensaje de ayuda y salir</translation>
+ </message>
+ <message>
+ <source>Print version and exit</source>
+ <translation>Imprimir versión y salir</translation>
+ </message>
+ <message>
+ <source>Prune cannot be configured with a negative value.</source>
+ <translation>Pode no se puede configurar con un valor negativo.</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -txindex.</source>
+ <translation>El modo recorte es incompatible con -txindex.</translation>
+ </message>
+ <message>
+ <source>Rebuild chain state and block index from the blk*.dat files on disk</source>
+ <translation>Reconstruir el estado de la cadena e indice de bloques a partir de los ficheros blk*.dat en disco</translation>
+ </message>
+ <message>
+ <source>Rebuild chain state from the currently indexed blocks</source>
+ <translation>Reconstruir el estado de la cadena a partir de los bloques indexados</translation>
+ </message>
+ <message>
+ <source>Rewinding blocks...</source>
+ <translation>Verificando bloques...</translation>
+ </message>
+ <message>
+ <source>Set database cache size in megabytes (%d to %d, default: %d)</source>
+ <translation>Asignar tamaño de cache en megabytes (entre %d y %d; predeterminado: %d)</translation>
+ </message>
+ <message>
+ <source>Set maximum block size in bytes (default: %d)</source>
+ <translation>Establecer tamaño máximo de bloque en bytes (predeterminado: %d)</translation>
+ </message>
+ <message>
+ <source>Specify wallet file (within data directory)</source>
+ <translation>Especificar archivo de monedero (dentro del directorio de datos)</translation>
+ </message>
+ <message>
+ <source>The source code is available from %s.</source>
+ <translation>El código fuente esta disponible desde %s.</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation>No se ha podido conectar con %s en este equipo. %s es posible que este todavia en ejecución.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
+ <translation>El argumento -benchmark no es soportado y ha sido ignorado, utiliza -debug=bench</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -debugnet ignored, use -debug=net.</source>
+ <translation>Parámetros no compatibles -debugnet ignorados , use -debug = red.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -tor found, use -onion.</source>
+ <translation>Parámetros no compatibles -tor encontrados, use -onion .</translation>
+ </message>
+ <message>
+ <source>Use UPnP to map the listening port (default: %u)</source>
+ <translation>Usar UPnP para asignar el puerto de escucha (predeterminado:: %u)</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>
+ <message>
+ <source>Verifying blocks...</source>
+ <translation>Verificando bloques...</translation>
+ </message>
+ <message>
+ <source>Verifying wallet...</source>
+ <translation>Verificando monedero...</translation>
+ </message>
+ <message>
+ <source>Wallet %s resides outside data directory %s</source>
+ <translation>El monedero %s se encuentra fuera del directorio de datos %s</translation>
+ </message>
+ <message>
+ <source>Wallet debugging/testing options:</source>
+ <translation>Opciones de depuración/pruebas de monedero:</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>Es necesario reescribir el monedero: reiniciar %s para completar</translation>
+ </message>
+ <message>
+ <source>Wallet options:</source>
+ <translation>Opciones de monedero:</translation>
+ </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>Permitir conexiones JSON-RPC de origen especificado. Válido para son una sola IP (por ejemplo 1.2.3.4), una red/máscara de red (por ejemplo 1.2.3.4/255.255.255.0) o una red/CIDR (e.g. 1.2.3.4/24). Esta opción se puede especificar varias veces</translation>
+ </message>
+ <message>
+ <source>Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6</source>
+ <translation>Ligar a las direcciones especificadas y poner en lista blanca a los equipos conectados a ellas. Usar la notación para IPv6 [host]:puerto.</translation>
+ </message>
+ <message>
+ <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>Ligar a las direcciones especificadas para escuchar por conexiones JSON-RPC. Usar la notación para IPv6 [host]:puerto. Esta opción se puede especificar múltiples veces (por defecto: ligar a todas las interfaces)</translation>
+ </message>
+ <message>
+ <source>Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)</source>
+ <translation>Crear nuevos archivos con permisos por defecto del sistema, en lugar de umask 077 (sólo efectivo con la funcionalidad de monedero desactivada)</translation>
+ </message>
+ <message>
+ <source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source>
+ <translation>Descubra direcciones IP propias (por defecto: 1 cuando se escucha y nadie -externalip o -proxy)</translation>
+ </message>
+ <message>
+ <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
+ <translation>Error: la escucha para conexiones entrantes falló (la escucha regresó el error %s)</translation>
+ </message>
+ <message>
+ <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>Ejecutar un comando cuando se reciba una alerta importante o cuando veamos un fork demasiado largo (%s en cmd se reemplazará por el mensaje)</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>Las comisiones (en %s/kB) mas pequeñas que esto se consideran como cero comisión para la retransmisión, minería y creación de la transacción (predeterminado: %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>Si el pago de comisión no está establecido, incluir la cuota suficiente para que las transacciones comiencen la confirmación en una media de n bloques ( por defecto :%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>Cantidad no válida para -maxtxfee=&lt;amount&gt;: '%s' (debe ser por lo menos la cuota de comisión mínima de %s para prevenir transacciones atascadas)</translation>
+ </message>
+ <message>
+ <source>Maximum size of data in data carrier transactions we relay and mine (default: %u)</source>
+ <translation>El tamaño máximo de los datos en las operaciones de transporte de datos que transmitimos y el mio (default: %u)</translation>
+ </message>
+ <message>
+ <source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
+ <translation>Aleatorizar las credenciales para cada conexión proxy. Esto habilita la Tor stream isolation (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
+ <translation>Establecer tamaño máximo de las transacciones de alta prioridad/baja comisión en bytes (predeterminado: %d)</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation>Monto de transacción muy pequeña luego de la deducción por comisión</translation>
+ </message>
+ <message>
+ <source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
+ <translation>Usar tras BIP32 la generación de llave determinística jerárquica (HD) . Solo tiene efecto durante el primer inicio/generación del monedero</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>A los equipos en lista blanca no se les pueden prohibir los ataques DoS y sus transacciones siempre son retransmitidas, incluso si ya están en el mempool, es útil por ejemplo para un gateway.</translation>
+ </message>
+ <message>
+ <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
+ <translation>Necesitas reconstruir la base de datos utilizando -reindex para volver al modo sin recorte. Esto volverá a descargar toda la cadena de bloques</translation>
+ </message>
+ <message>
+ <source>(default: %u)</source>
+ <translation>(por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Accept public REST requests (default: %u)</source>
+ <translation>Aceptar solicitudes públicas en FERIADOS (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Automatically create Tor hidden service (default: %d)</source>
+ <translation>Automáticamente crea el servicio Tor oculto (por defecto: %d)</translation>
+ </message>
+ <message>
+ <source>Connect through SOCKS5 proxy</source>
+ <translation>Conectar usando SOCKS5 proxy</translation>
+ </message>
+ <message>
+ <source>Error reading from database, shutting down.</source>
+ <translation>Error al leer la base de datos, cerrando.</translation>
+ </message>
+ <message>
+ <source>Imports blocks from external blk000??.dat file on startup</source>
+ <translation>Importa los bloques desde un archivo externo blk000?.dat</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Información</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
+ <translation>Cantidad inválida para -paytxfee=&lt;amount&gt;: '%s' (debe ser por lo menos %s)</translation>
+ </message>
+ <message>
+ <source>Invalid netmask specified in -whitelist: '%s'</source>
+ <translation>Máscara de red inválida especificada en -whitelist: '%s'</translation>
+ </message>
+ <message>
+ <source>Keep at most &lt;n&gt; unconnectable transactions in memory (default: %u)</source>
+ <translation>Mantener como máximo &lt;n&gt; transacciones no conectables en memoria (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Need to specify a port with -whitebind: '%s'</source>
+ <translation>Necesita especificar un puerto con -whitebind: '%s'</translation>
+ </message>
+ <message>
+ <source>Node relay options:</source>
+ <translation>Opciones de nodos de retransmisión:</translation>
+ </message>
+ <message>
+ <source>RPC server options:</source>
+ <translation>Opciones de servidor RPC:</translation>
+ </message>
+ <message>
+ <source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
+ <translation>Reduciendo -maxconnections de %d a %d, debido a limitaciones del sistema.</translation>
+ </message>
+ <message>
+ <source>Rescan the block chain for missing wallet transactions on startup</source>
+ <translation>Rescanea la cadena de bloques para transacciones perdidas de la cartera</translation>
+ </message>
+ <message>
+ <source>Send trace/debug info to console instead of debug.log file</source>
+ <translation>Enviar información de trazas/depuración a la consola en lugar de al archivo debug.log</translation>
+ </message>
+ <message>
+ <source>Send transactions as zero-fee transactions if possible (default: %u)</source>
+ <translation>Mandar transacciones como comisión-cero si es posible (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Show all debugging options (usage: --help -help-debug)</source>
+ <translation>Muestra todas las opciones de depuración (uso: --help -help-debug)</translation>
+ </message>
+ <message>
+ <source>Shrink debug.log file on client startup (default: 1 when no -debug)</source>
+ <translation>Reducir el archivo debug.log al iniciar el cliente (predeterminado: 1 sin -debug)</translation>
+ </message>
+ <message>
+ <source>Signing transaction failed</source>
+ <translation>Transacción falló</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation>Cantidad de la transacción demasiado pequeña para pagar la comisión</translation>
+ </message>
+ <message>
+ <source>This is experimental software.</source>
+ <translation>Este software es experimental.</translation>
+ </message>
+ <message>
+ <source>Tor control port password (default: empty)</source>
+ <translation>Contraseña del puerto de control de Tor (predeterminado: vacio)</translation>
+ </message>
+ <message>
+ <source>Tor control port to use if onion listening enabled (default: %s)</source>
+ <translation>Puerto de control de Tor a utilizar si la escucha de onion esta activada (predeterminado: %s)</translation>
+ </message>
+ <message>
+ <source>Transaction amount too small</source>
+ <translation>Cantidad de la transacción demasiado pequeña</translation>
+ </message>
+ <message>
+ <source>Transaction too large for fee policy</source>
+ <translation>Operación demasiado grande para la política de tasas</translation>
+ </message>
+ <message>
+ <source>Transaction too large</source>
+ <translation>Transacción demasiado grande, intenta dividirla en varias.</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer (bind returned error %s)</source>
+ <translation>No es posible conectar con %s en este sistema (bind ha dado el error %s)</translation>
+ </message>
+ <message>
+ <source>Upgrade wallet to latest format on startup</source>
+ <translation>Actualizar el monedero al último formato al inicio</translation>
+ </message>
+ <message>
+ <source>Username for JSON-RPC connections</source>
+ <translation>Nombre de usuario para las conexiones JSON-RPC
+</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Aviso</translation>
+ </message>
+ <message>
+ <source>Warning: unknown new rules activated (versionbit %i)</source>
+ <translation>Advertencia: nuevas reglas desconocidas activadas (versionbit %i)</translation>
+ </message>
+ <message>
+ <source>Whether to operate in a blocks only mode (default: %u)</source>
+ <translation>Si se debe o no operar en un modo de solo bloques (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Zapping all transactions from wallet...</source>
+ <translation>Eliminando todas las transacciones del monedero...</translation>
+ </message>
+ <message>
+ <source>ZeroMQ notification options:</source>
+ <translation>Opciones de notificación ZeroQM:</translation>
+ </message>
+ <message>
+ <source>Password for JSON-RPC connections</source>
+ <translation>Contraseña para las conexiones JSON-RPC
+</translation>
+ </message>
+ <message>
+ <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
+ <translation>Ejecutar un comando cuando cambia el mejor bloque (%s en cmd se sustituye por el hash de bloque)</translation>
+ </message>
+ <message>
+ <source>Allow DNS lookups for -addnode, -seednode and -connect</source>
+ <translation>Permitir búsquedas DNS para -addnode, -seednode y -connect</translation>
+ </message>
+ <message>
+ <source>Loading addresses...</source>
+ <translation>Cargando direcciones...</translation>
+ </message>
+ <message>
+ <source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
+ <translation>(1 = mantener los meta datos de transacción, por ejemplo: propietario e información de pago, 2 = omitir los metadatos)</translation>
+ </message>
+ <message>
+ <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
+ <translation>-maxtxfee tiene un ajuste muy elevado! Comisiones muy grandes podrían ser pagadas en una única transaccion.</translation>
+ </message>
+ <message>
+ <source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
+ <translation>No mantener transacciones en la memoria mas de &lt;n&gt; horas (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Bytes equivalentes por sigop en transacciones para retrasmisión y minado (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
+ <translation>Las comisiones (en %s/kB) menores que esto son consideradas de cero comision para la creacion de transacciones (predeterminado: %s)</translation>
+ </message>
+ <message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>Fuerza la retransmisión de transacciones desde nodos en la lista blanca incluso si violan la política de retransmisiones local (predeterminado: %d)</translation>
+ </message>
+ <message>
+ <source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
+ <translation>Nivel de rigor en la verificación de bloques de -checkblocks (0-4; predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)</source>
+ <translation>Mantener el índice completo de transacciones, usado por la llamada rpc de getrawtransaction (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Number of seconds to keep misbehaving peers from reconnecting (default: %u)</source>
+ <translation>Número de segundos en que se evita la reconexión de pares con mal comportamiento (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Output debugging information (default: %u, supplying &lt;category&gt; is optional)</source>
+ <translation>Mostrar depuración (por defecto: %u, proporcionar &lt;category&gt; es opcional)</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>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>
+ <message>
+ <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source>
+ <translation>Error: argumento -socks encontrado. El ajuste de la versión SOCKS ya no es posible, sólo proxies SOCKS5 son compatibles.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
+ <translation>El argumento no soportado -whitelistalwaysrelay ha sido ignorado, utiliza -whitelistrelay y/o -whitelistforcerelay.</translation>
+ </message>
+ <message>
+ <source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)</source>
+ <translation>Usar distintos proxys SOCKS5 para comunicarse vía Tor de forma anónima (Por defecto: %s)</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
+ <translation>Advertencia: Se están minando versiones de bloques desconocidas! Es posible que normas desconocidas estén activas</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>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>(default: %s)</source>
+ <translation>(predeterminado: %s)</translation>
+ </message>
+ <message>
+ <source>Always query for peer addresses via DNS lookup (default: %u)</source>
+ <translation>Siempre consultar direcciones de otros equipos por medio de DNS lookup (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>How many blocks to check at startup (default: %u, 0 = all)</source>
+ <translation>Cuántos bloques comprobar al iniciar (predeterminado: %u, 0 = todos)</translation>
+ </message>
+ <message>
+ <source>Include IP addresses in debug output (default: %u)</source>
+ <translation>Incluir direcciones IP en la salida de depuración (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Invalid -proxy address: '%s'</source>
+ <translation>Dirección -proxy inválida: '%s'</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>
+ <message>
+ <source>Listen for connections on &lt;port&gt; (default: %u or testnet: %u)</source>
+ <translation>Escuchar conexiones en &lt;puerto&gt; (predeterminado: %u o testnet: %u)</translation>
+ </message>
+ <message>
+ <source>Maintain at most &lt;n&gt; connections to peers (default: %u)</source>
+ <translation>Mantener como máximo &lt;n&gt; conexiones a pares (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Make the wallet broadcast transactions</source>
+ <translation>Realiza las operaciones de difusión del monedero</translation>
+ </message>
+ <message>
+ <source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
+ <translation>Búfer de recepción máximo por conexión, &lt;n&gt;*1000 bytes (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Maximum per-connection send buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
+ <translation>Búfer de recepción máximo por conexión, , &lt;n&gt;*1000 bytes (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Prepend debug output with timestamp (default: %u)</source>
+ <translation>Anteponer marca temporal a la información de depuración (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Relay and mine data carrier transactions (default: %u)</source>
+ <translation>Retransmitir y minar transacciones de transporte de datos (por defecto: %u)</translation>
+ </message>
+ <message>
+ <source>Relay non-P2SH multisig (default: %u)</source>
+ <translation>Relay non-P2SH multisig (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>
+ <message>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Establecer peso máximo bloque BIP141 (predeterminado: %d)</translation>
+ </message>
+ <message>
+ <source>Set the number of threads to service RPC calls (default: %d)</source>
+ <translation>Establecer el número de procesos para llamadas del servicio RPC (por defecto: %d)</translation>
+ </message>
+ <message>
+ <source>Specify configuration file (default: %s)</source>
+ <translation>Especificar archivo de configuración (por defecto: %s)</translation>
+ </message>
+ <message>
+ <source>Specify connection timeout in milliseconds (minimum: 1, default: %d)</source>
+ <translation>Especificar tiempo de espera de la conexión (mínimo: 1, por defecto: %d)</translation>
+ </message>
+ <message>
+ <source>Specify pid file (default: %s)</source>
+ <translation>Especificar archivo pid (predeterminado: %s)</translation>
+ </message>
+ <message>
+ <source>Spend unconfirmed change when sending transactions (default: %u)</source>
+ <translation>Usar cambio aún no confirmado al enviar transacciones (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Starting network threads...</source>
+ <translation>Iniciando funciones de red...</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>Unknown network specified in -onlynet: '%s'</source>
+ <translation>La red especificada en -onlynet '%s' es desconocida</translation>
+ </message>
+ <message>
+ <source>Insufficient funds</source>
+ <translation>Fondos insuficientes</translation>
+ </message>
+ <message>
+ <source>Loading block index...</source>
+ <translation>Cargando el índice de bloques...</translation>
+ </message>
+ <message>
+ <source>Add a node to connect to and attempt to keep the connection open</source>
+ <translation>Añadir un nodo al que conectarse y tratar de mantener la conexión abierta</translation>
+ </message>
+ <message>
+ <source>Loading wallet...</source>
+ <translation>Cargando monedero...</translation>
+ </message>
+ <message>
+ <source>Cannot downgrade wallet</source>
+ <translation>No se puede cambiar a una versión mas antigua el monedero</translation>
+ </message>
+ <message>
+ <source>Cannot write default address</source>
+ <translation>No se puede escribir la dirección predeterminada</translation>
+ </message>
+ <message>
+ <source>Rescanning...</source>
+ <translation>Reexplorando...</translation>
+ </message>
+ <message>
+ <source>Done loading</source>
+ <translation>Se terminó de cargar</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_es_MX.ts b/src/qt/locale/bitcoin_es_MX.ts
index 0a6ea1e1dd..bf8f0ceb88 100644
--- a/src/qt/locale/bitcoin_es_MX.ts
+++ b/src/qt/locale/bitcoin_es_MX.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Borrar</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Repita la nueva contraseña</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -246,7 +249,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>La cartera esta &lt;b&gt;encriptada&lt;/b&gt; y &lt;b&gt;bloqueada&lt;/b&gt; actualmente </translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -262,10 +265,6 @@
<translation>Monto:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridad:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Cuota:</translation>
</message>
@@ -289,11 +288,7 @@
<source>Confirmed</source>
<translation>Confirmado </translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioridad</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -308,7 +303,7 @@
<source>&amp;Address</source>
<translation>&amp;Dirección</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -347,6 +342,13 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -376,6 +378,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -386,6 +391,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>Debug window</source>
@@ -427,6 +438,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -445,10 +459,6 @@
<translation>Monto:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridad:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Cuota:</translation>
</message>
@@ -521,6 +531,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
<message>
<source>Do not shut down the computer until this window disappears.</source>
@@ -553,16 +566,38 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Este panel muestras una descripción detallada de la transacción</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Enviar monedas</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_es_UY.ts b/src/qt/locale/bitcoin_es_UY.ts
index c565a63cd8..61bf9ad7ed 100644
--- a/src/qt/locale/bitcoin_es_UY.ts
+++ b/src/qt/locale/bitcoin_es_UY.ts
@@ -33,7 +33,10 @@
<source>&amp;Delete</source>
<translation>&amp;Borrar</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -48,7 +51,7 @@
<source>Repeat new passphrase</source>
<translation>Repetir nueva contraseña</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -189,7 +192,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>El Monedero esta &lt;b&gt;cifrado&lt;/b&gt; y actualmente &lt;b&gt;bloqueado&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -205,10 +208,6 @@
<translation>AMonto:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridad:</translation>
- </message>
- <message>
<source>Change:</source>
<translation>Cambio:</translation>
</message>
@@ -220,11 +219,7 @@
<source>Confirmed</source>
<translation>Confirmado</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioridad</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -239,7 +234,7 @@
<source>&amp;Address</source>
<translation>&amp;Direccion </translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -254,6 +249,13 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -275,12 +277,21 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>&amp;Information</source>
@@ -302,6 +313,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -320,10 +334,6 @@
<translation>AMonto:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridad:</translation>
- </message>
- <message>
<source>Change:</source>
<translation>Cambio:</translation>
</message>
@@ -372,6 +382,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -400,12 +413,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_es_VE.ts b/src/qt/locale/bitcoin_es_VE.ts
index 432adc57ee..f465b949a2 100644
--- a/src/qt/locale/bitcoin_es_VE.ts
+++ b/src/qt/locale/bitcoin_es_VE.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Borrar</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Repetir nueva frase de contraseña</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -175,10 +178,6 @@
<translation>Opciones de línea de comandos</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 y %2</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 detrás</translation>
</message>
@@ -226,7 +225,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>La billetera está encriptada y bloqueada recientemente</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -246,10 +245,6 @@
<translation>Monto:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridad:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Comisión:</translation>
</message>
@@ -297,11 +292,7 @@
<source>Confirmed</source>
<translation>Confirmado</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioridad</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -324,7 +315,7 @@
<source>&amp;Address</source>
<translation>&amp;Dirección</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -391,6 +382,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -408,7 +402,7 @@
<source>Select payment request file</source>
<translation>Seleccionar archivo de solicitud de pago</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -448,6 +442,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -456,6 +453,16 @@
<source>Amount</source>
<translation>Monto</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 y %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -495,6 +502,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Quantity:</source>
@@ -509,10 +519,6 @@
<translation>Monto:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridad:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Comisión:</translation>
</message>
@@ -537,6 +543,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -549,12 +558,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -593,10 +620,6 @@
<translation>Borrar todas las transacciones de la billetera y solo recuperar aquellas partes de la cadena de bloques a través de -rescan en el inicio del sistema.</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuido bajo la licensia de software MIT, ver el archivo adjunto COPYING o &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Ejecutar comando cuando una transacción de la billetera cambia (%s en cmd es reemplazado por TxID)</translation>
</message>
@@ -605,18 +628,6 @@
<translation>Fija el número de verificación de hilos de script (%u a %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</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 compilación de prueba pre-lanzamiento - use bajo su propio riesgo - no utilizar para aplicaciones de minería o mercantes</translation>
- </message>
- <message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Aviso: ¡La red no parece estar totalmente de acuerdo! Algunos mineros parecen estar teniendo inconvenientes.</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: ¡No parecen estar totalmente de acuerdo con nuestros compañeros! Puede que tengas que actualizar, u otros nodos tengan que actualizarce.</translation>
- </message>
- <message>
<source>Information</source>
<translation>Información</translation>
</message>
diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts
index 0d659fd719..313d5e3be1 100644
--- a/src/qt/locale/bitcoin_et.ts
+++ b/src/qt/locale/bitcoin_et.ts
@@ -2,6 +2,10 @@
<context>
<name>AddressBookPage</name>
<message>
+ <source>Right-click to edit address or label</source>
+ <translation>Paremkliki aadressi või sildi muutmiseks</translation>
+ </message>
+ <message>
<source>Create a new address</source>
<translation>Loo uus aadress</translation>
</message>
@@ -37,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Kustuta</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Vali aadress millele mündid saata</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Vali aadress müntide vastuvõtmiseks</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>V&amp;ali</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Saatvad aadressid</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Vastuvõtvad aadressid</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>Need on sinu Bitcoin aadressid maksete saatmiseks. Ennem müntide saatmist kontrolli alati summat ja makse saaja aadressi.</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>Need on sinu Bitcoin aadressid sisenevate maksete vastu võtmiseks. Soovitav on iga tehingu tarbeks kasutada uut aadressi.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopeeri Aadress</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopeeri &amp;Silt</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Muuda</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Ekspordi Aadresside Nimekiri</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Komadega eraldatud väärtuste fail (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksport ebaõnnestus.</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Tõrge aadressi nimekirja salvestamisel %1. Palun proovi uuesti.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Märge</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Aadress</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(märge puudub)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -56,9 +131,93 @@
<source>Repeat new passphrase</source>
<translation>Korda salafraasi</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>Sisesta uus salafraas rahakotti.&lt;br/&gt;Kasuta salafraasi millles on&lt;b&gt;kümme või rohkem juhuslikku sümbolit&lt;b&gt;,või&lt;b&gt;kaheksa või rohkem sõna&lt;b/&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Krüpteeri rahakott</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Antud operatsioon vajab rahakoti lahtilukustamiseks salafraasi.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Ava rahakoti lukk</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Antud operatsioon vajab rahakoti dekrüpteerimiseks salafraasi.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dekrüpteeri rahakott</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Vaheta salafraasi</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Sisesta vana salafraas ja uus salafraas rahakotti.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Kinnita rahakoti krüpteerimine.</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>Hoiatus:Kui sa krüpteerid oma rahakoti ja kaotad salafraasi, siis sa&lt;b&gt;KAOTAD OMA BITCOINID&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Kas oled kindel, et soovid rahakoti krüpteerida?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Rahakott krüpteeritud</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Rahakoti krüpteerimine ebaõnnestus</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Rahakoti krüpteerimine ebaõnnestus sisemise tõrke tõttu. Sinu rahakott ei ole krüpteeritud.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Sisestatud salafraasid ei kattu.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Rahakoti lahtilukustamine ebaõnnestus</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Rahakoti dekrüpteerimiseks sisestatud salafraas ei ole õige.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Rahakoti dekrüpteerimine ebaõnnestus</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Rahakoti salafraas on edukalt vahetatud.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Hoiatus:Klaviatuuri suurtähelukk on peal.</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Võrgumask</translation>
+ </message>
</context>
<context>
<name>BitcoinGUI</name>
@@ -95,6 +254,10 @@
<translation>Väljumine</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>&amp;Teave %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>Teave &amp;Qt kohta</translation>
</message>
@@ -140,7 +303,7 @@
</message>
<message>
<source>&amp;Debug window</source>
- <translation>&amp;Debugimise aken</translation>
+ <translation>&amp;Silumise aken</translation>
</message>
<message>
<source>Open debugging and diagnostic console</source>
@@ -164,7 +327,7 @@
</message>
<message>
<source>&amp;Receive</source>
- <translation>&amp;Saama</translation>
+ <translation>&amp;Võta vastu</translation>
</message>
<message>
<source>&amp;Show / Hide</source>
@@ -203,28 +366,32 @@
<translation>Vahelehe tööriistariba</translation>
</message>
<message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation>Loo maksepäring (genereerib QR koodid ja bitcoini: URId)</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI or payment request</source>
+ <translation>Ava bitcoini: URI või maksepäring</translation>
+ </message>
+ <message>
<source>&amp;Command-line options</source>
<translation>Käsurea valikud</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>
+ <source>%n active connection(s) to Bitcoin network</source>
+ <translation><numerusform>%n aktiivne ühendus Bitcoini võrku</numerusform><numerusform>%n aktiivset ühendust Bitcoini võrku</numerusform></translation>
</message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n nädal</numerusform><numerusform>%n nädalat</numerusform></translation>
+ <message>
+ <source>Indexing blocks on disk...</source>
+ <translation>Kõvakettal olevate plokkide indekseerimine...</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 ja %2</translation>
+ <source>Processing blocks on disk...</source>
+ <translation>Kõvakettal olevate plokkide töötlemine...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n aasta</numerusform><numerusform>%n aastat</numerusform></translation>
+ <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>
</message>
<message>
<source>%1 behind</source>
@@ -255,8 +422,12 @@
<translation>Ajakohane</translation>
</message>
<message>
+ <source>%1 client</source>
+ <translation>%1 klient</translation>
+ </message>
+ <message>
<source>Catching up...</source>
- <translation>Jõuan...</translation>
+ <translation>Jõuan järgi...</translation>
</message>
<message>
<source>Date: %1
@@ -304,7 +475,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Rahakott on &lt;b&gt;krüpteeritud&lt;/b&gt; ning hetkel &lt;b&gt;suletud&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -312,6 +483,10 @@
<translation>Kogus:</translation>
</message>
<message>
+ <source>Bytes:</source>
+ <translation>Baiti:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation>Summa:</translation>
</message>
@@ -320,18 +495,106 @@
<translation>Tasu:</translation>
</message>
<message>
+ <source>Dust:</source>
+ <translation>Puru:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Peale tehingutasu:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Vahetusraha:</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation>Puu režiim</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation>Loetelu režiim</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation>Kogus</translation>
</message>
<message>
+ <source>Received with label</source>
+ <translation>Vastuvõetud märgisega</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation>Vastuvõetud aadressiga</translation>
+ </message>
+ <message>
<source>Date</source>
<translation>Kuupäev</translation>
</message>
<message>
+ <source>Confirmations</source>
+ <translation>Kinnitused</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation>Kinnitatud</translation>
</message>
- </context>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopeeri aadress</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopeeri märgis</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopeeri summa</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopeeri tehingu ID</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopeeri kogus</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopeeri tehingutasu</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopeeri baidid</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopeeri puru</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopeeri vahetusraha</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 lukustatud)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>jah</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>ei</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(märgis puudub)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(vahetusraha)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -346,6 +609,38 @@
<source>&amp;Address</source>
<translation>&amp;Aadress</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Uus vastu võttev aadress</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Uus saatev aadress</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Muuda vastuvõtvat aadressi</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Muuda saatvat aadressi</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Sisestatud aadress "%1" ei ole korrektne Bitcoin aadress.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Sisestatud aadress "%1" on juba aadressi raamatus.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Rahakoti lahtilukustamine ebaõnnestus.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Uue võtme genereerimine ebaõnnestus.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -372,6 +667,14 @@
<source>command-line options</source>
<translation>käsurea valikud</translation>
</message>
+ <message>
+ <source>UI Options:</source>
+ <translation>Kasutajaliidese Suvandid:</translation>
+ </message>
+ <message>
+ <source>Show splash screen on startup (default: %u)</source>
+ <translation>Käivitamisel kuva laadimisekraani (vaikimisi %u)</translation>
+ </message>
</context>
<context>
<name>Intro</name>
@@ -385,6 +688,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Viimane ploki aeg</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Peida</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -394,7 +712,15 @@
<source>URI:</source>
<translation>URI:</translation>
</message>
- </context>
+ <message>
+ <source>Select payment request file</source>
+ <translation>Vali maksepäringu fail</translation>
+ </message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Vali maksepäringu fail mida avada</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
<message>
@@ -450,10 +776,26 @@
<translation>Proxi port (nt 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;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>
@@ -494,6 +836,10 @@
<translation>vaikeväärtus</translation>
</message>
<message>
+ <source>none</source>
+ <translation>puudub</translation>
+ </message>
+ <message>
<source>Confirm options reset</source>
<translation>Kinnita valikute algseadistamine</translation>
</message>
@@ -513,6 +859,10 @@
<translation>Kuvatav info ei pruugi olla ajakohane. Ühenduse loomisel süngitakse sinu rahakott automaatselt Bitconi võrgustikuga, kuid see toiming on hetkel lõpetamata.</translation>
</message>
<message>
+ <source>Pending:</source>
+ <translation>Ootel:</translation>
+ </message>
+ <message>
<source>Immature:</source>
<translation>Ebaküps:</translation>
</message>
@@ -521,11 +871,34 @@
<translation>Mitte aegunud mine'itud jääk</translation>
</message>
<message>
+ <source>Total:</source>
+ <translation>Kokku:</translation>
+ </message>
+ <message>
<source>Recent transactions</source>
<translation>Hiljutised tehingud</translation>
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Maksepäringu tõrge</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Maksepäring tagasi lükatud</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Maksepäring aegunud.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Kinnitamata maksepäringud kohandatud makse scriptidele ei ole toetatud.</translation>
+ </message>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -538,6 +911,40 @@
<source>N/A</source>
<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>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Salvesta QR Kood</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -562,6 +969,10 @@
<translation>Üldine</translation>
</message>
<message>
+ <source>Using BerkeleyDB version</source>
+ <translation>Kasutab BerkeleyDB versiooni</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>Käivitamise hetk</translation>
</message>
@@ -586,6 +997,10 @@
<translation>Plokkide hetkearv</translation>
</message>
<message>
+ <source>Memory usage</source>
+ <translation>Mälu kasutus</translation>
+ </message>
+ <message>
<source>Received</source>
<translation>Vastuvõetud</translation>
</message>
@@ -602,6 +1017,14 @@
<translation>Versioon</translation>
</message>
<message>
+ <source>Synced Headers</source>
+ <translation>Sünkroniseeritud Päised</translation>
+ </message>
+ <message>
+ <source>Synced Blocks</source>
+ <translation>Sünkroniseeritud Plokid</translation>
+ </message>
+ <message>
<source>Services</source>
<translation>Teenused</translation>
</message>
@@ -619,7 +1042,7 @@
</message>
<message>
<source>Debug log file</source>
- <translation>Debugimise logifail</translation>
+ <translation>Silumise logifail</translation>
</message>
<message>
<source>Clear console</source>
@@ -649,7 +1072,27 @@
<source>%1 GB</source>
<translation>%1 GB</translation>
</message>
- </context>
+ <message>
+ <source>Inbound</source>
+ <translation>Sisenev</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <translation>Väljuv</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Jah</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Ei</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation>Teadmata</translation>
+ </message>
+</context>
<context>
<name>ReceiveCoinsDialog</name>
<message>
@@ -665,6 +1108,10 @@
<translation>&amp;Sõnum:</translation>
</message>
<message>
+ <source>Clear all fields of the form.</source>
+ <translation>Puhasta kõik vormi väljad.</translation>
+ </message>
+ <message>
<source>Show</source>
<translation>Näita</translation>
</message>
@@ -672,13 +1119,76 @@
<source>Remove</source>
<translation>Eemalda</translation>
</message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopeeri märgis</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Kopeeri sõnum</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopeeri summa</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>QR Code</source>
+ <translation>QR Kood</translation>
+ </message>
+ <message>
<source>Copy &amp;Address</source>
<translation>&amp;Kopeeri Aadress</translation>
</message>
+ <message>
+ <source>Payment information</source>
+ <translation>Makse Informatsioon</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Aadress</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Summa</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Silt</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Sõnum</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>URI liiga pikk, proovi vähendada märke / sõnumi pikkust.</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Kuupäev</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Silt</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Sõnum</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(märge puudub)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(sõnum puudub)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -687,6 +1197,14 @@
<translation>Müntide saatmine</translation>
</message>
<message>
+ <source>Inputs...</source>
+ <translation>Sisendid...</translation>
+ </message>
+ <message>
+ <source>automatically selected</source>
+ <translation>automaatselt valitud</translation>
+ </message>
+ <message>
<source>Insufficient funds!</source>
<translation>Liiga suur summa</translation>
</message>
@@ -695,6 +1213,10 @@
<translation>Kogus:</translation>
</message>
<message>
+ <source>Bytes:</source>
+ <translation>Baiti:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation>Summa:</translation>
</message>
@@ -703,6 +1225,14 @@
<translation>Tasu:</translation>
</message>
<message>
+ <source>After Fee:</source>
+ <translation>Peale tehingutasu:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Vahetusraha:</translation>
+ </message>
+ <message>
<source>Transaction Fee:</source>
<translation>Tehingu tasu:</translation>
</message>
@@ -711,6 +1241,10 @@
<translation>Vali...</translation>
</message>
<message>
+ <source>per kilobyte</source>
+ <translation>kilobaidi kohta</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>Peida</translation>
</message>
@@ -735,6 +1269,14 @@
<translation>Lisa &amp;Saaja</translation>
</message>
<message>
+ <source>Clear all fields of the form.</source>
+ <translation>Puhasta kõik vormi väljad.</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Puru:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Puhasta &amp;Kõik</translation>
</message>
@@ -750,6 +1292,58 @@
<source>S&amp;end</source>
<translation>S&amp;aada</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopeeri kogus</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopeeri summa</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopeeri tehingutasu</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopeeri baidid</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopeeri puru</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopeeri vahetusraha</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Oled kindel, et soovid saata?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>lisatud kui tehingutasu</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>või</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Saaja aadress ei ole korrektne. Palun kontrolli üle.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Maksepäring aegunud.</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Hoiatus: Ebakorrektne Bitcoin aadress</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(märgis puudub)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -766,6 +1360,10 @@
<translation>&amp;Märgis</translation>
</message>
<message>
+ <source>Choose previously used address</source>
+ <translation>Vali eelnevalt kasutatud aadress</translation>
+ </message>
+ <message>
<source>Alt+A</source>
<translation>Alt+A</translation>
</message>
@@ -778,6 +1376,10 @@
<translation>Alt+P</translation>
</message>
<message>
+ <source>S&amp;ubtract fee from amount</source>
+ <translation>L&amp;ahuta tehingutasu summast</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation>Sõnum:</translation>
</message>
@@ -787,8 +1389,23 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Jah</translation>
+ </message>
+</context>
+<context>
<name>ShutdownWindow</name>
- </context>
+ <message>
+ <source>%1 is shutting down...</source>
+ <translation>%1 lülitub välja...</translation>
+ </message>
+ <message>
+ <source>Do not shut down the computer until this window disappears.</source>
+ <translation>Ära lülita arvutit välja ennem kui see aken on kadunud.</translation>
+ </message>
+</context>
<context>
<name>SignVerifyMessageDialog</name>
<message>
@@ -800,6 +1417,14 @@
<translation>&amp;Allkirjastamise teade</translation>
</message>
<message>
+ <source>The Bitcoin address to sign the message with</source>
+ <translation>Bitcoin aadress millega sõnum allkirjastada</translation>
+ </message>
+ <message>
+ <source>Choose previously used address</source>
+ <translation>Vali eelnevalt kasutatud aadress</translation>
+ </message>
+ <message>
<source>Alt+A</source>
<translation>Alt+A</translation>
</message>
@@ -844,6 +1469,10 @@
<translation>&amp;Kinnita Sõnum</translation>
</message>
<message>
+ <source>The Bitcoin address the message was signed with</source>
+ <translation>Bitcoin aadress millega sõnum on allkirjastatud</translation>
+ </message>
+ <message>
<source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
<translation>Kinnita sõnum tõestamaks selle allkirjastatust määratud Bitcoini aadressiga.</translation>
</message>
@@ -855,6 +1484,54 @@
<source>Reset all verify message fields</source>
<translation>Tühjenda kõik sõnumi kinnitamise väljad</translation>
</message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Allkirja loomiseks vajuta "Allkirjasta Sõnum"</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>Sisestatud aadress ei ole korrektne</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Palun kontrolli aadressi ja proovi uuesti.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Rahakoti lahtilukustamine on katkestatud.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Sisestatud aadressi privaatvõti pole saadaval.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Sõnumi allkirjastamine ebaõnnestus.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Sõnum allkirjastatud</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Allkirja polnud võimalik dekodeerida.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Palun kontrolli allkirja ja proovi uuesti.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>Allkiri ei vastanud sõnumi krüptoräsile.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Sõnumi verifitseerimine ebaõnnestus.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Sõnum verifitseeritud.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -871,16 +1548,190 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/kinnitamata</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 kinnitust</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Olek</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Kuupäev</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Genereeritud</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>märgis</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>pole vastu võetud</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Tehingutasu</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Sõnum</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Kommentaar</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Kaupleja</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Sisendid</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Summa</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>tõene</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>väär</translation>
+ </message>
+</context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Paan kuvab tehingu detailid</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Kuupäev</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tüüp</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Silt</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Kinnitamata</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(silt puudub)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Kõik</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Täna</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Käesolev nädal</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Käesolev kuu</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Eelmine kuu</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Käesolev aasta</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Vahemik...</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Minimaalne summa</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopeeri aadress</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopeeri märgis</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopeeri summa</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopeeri tehingu ID</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Komadega eraldatud väärtuste fail (*.csv)</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Kuupäev</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tüüp</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Silt</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Aadress</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksport ebaõnnestus.</translation>
+ </message>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -907,10 +1758,6 @@
<translation>Tööta taustal ning aktsepteeri käsklusi</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Luba välisühendusi (vaikeväärtus: 1 kui puudub -proxy või -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoini tuumik</translation>
</message>
@@ -923,18 +1770,10 @@
<translation>Käivita käsklus, kui rahakoti tehing muutub (%s cmd's muudetakse TxID'ks)</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>See on test-versioon - kasutamine omal riisikol - ära kasuta mining'uks ega kaupmeeste programmides</translation>
- </message>
- <message>
<source>Block creation options:</source>
<translation>Blokeeri loomise valikud:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Ühendu ainult määratud node'i(de)ga</translation>
- </message>
- <message>
<source>Corrupted block database detected</source>
<translation>Tuvastati vigane bloki andmebaas</translation>
</message>
diff --git a/src/qt/locale/bitcoin_et_EE.ts b/src/qt/locale/bitcoin_et_EE.ts
new file mode 100644
index 0000000000..d96ffa42f5
--- /dev/null
+++ b/src/qt/locale/bitcoin_et_EE.ts
@@ -0,0 +1,747 @@
+<TS language="et_EE" version="2.1">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Create a new address</source>
+ <translation>Loo uus aadress</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation>&amp;Uus</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation>&amp;Kopeeri</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>Kustuta valitud aadress nimekirjast</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation>&amp;Kustuta</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Muuda</translation>
+ </message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Silt</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Aadress</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(silt puudub)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Enter passphrase</source>
+ <translation>Sisesta parool</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation>Uus parool</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation>Korda uut parooli</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Krüpteeri rahakott</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dekrüpteeri rahakott</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Muuda parooli</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Kas oled kindel, et soovid rahakoti krüpteerida?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Rahakott krüpteeritud</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Rahakoti krüpteerimine ebaõnnestus</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Rahakoti krüpteerimine ebaõnnestus sisemise vea tõttu. Sinu rahakotti ei krüpteeritud.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Sisestatud paroolid ei kattu.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Rahakoti dekrüpteerimine ebaõnnestus</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Rahakoti parooli vahetus õnnestus.</translation>
+ </message>
+ </context>
+<context>
+ <name>BanTableModel</name>
+ </context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>Synchronizing with network...</source>
+ <translation>Võrguga sünkroniseerimine...</translation>
+ </message>
+ <message>
+ <source>&amp;Overview</source>
+ <translation>&amp;Ülevaade</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>Ava &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk...</source>
+ <translation>Kõvakettal olevate plokkide reindekseerimine...</translation>
+ </message>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Rahakott</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation>&amp;Fail</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation>&amp;Abi</translation>
+ </message>
+ <message>
+ <source>%1 behind</source>
+ <translation>%1 ajast maas</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation>Hilisemad transaktsioonid ei ole veel nähtavad.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Viga</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Hoiatus</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Informatsioon</translation>
+ </message>
+ </context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>Amount:</source>
+ <translation>Kogus</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kogus</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Kuupäev</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation>Kinnitused</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Kinnitatud</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopeeri aadress</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopeeri kogus</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopeeri transaktsiooni ID</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>jah</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>ei</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(silt puudub)</translation>
+ </message>
+ </context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Uue võtme genereerimine ebaõnnestus.</translation>
+ </message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
+ <message>
+ <source>name</source>
+ <translation>nimi</translation>
+ </message>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation>versioon</translation>
+ </message>
+ <message>
+ <source>Command-line options</source>
+ <translation>Käsurea valikud</translation>
+ </message>
+ <message>
+ <source>Usage:</source>
+ <translation>Kasutus:</translation>
+ </message>
+ <message>
+ <source>command-line options</source>
+ <translation>käsurea valikud</translation>
+ </message>
+ </context>
+<context>
+ <name>Intro</name>
+ <message>
+ <source>Welcome</source>
+ <translation>Tere tulemast</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Viga</translation>
+ </message>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
+ <name>OpenURIDialog</name>
+ </context>
+<context>
+ <name>OptionsDialog</name>
+ <message>
+ <source>Options</source>
+ <translation>Valikud</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <translation>MB</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation>&amp;Võrk</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;OK</source>
+ <translation>&amp;OK</translation>
+ </message>
+ </context>
+<context>
+ <name>OverviewPage</name>
+ <message>
+ <source>Pending:</source>
+ <translation>Ootel:</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation>Kokku:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation>Hiljutised transaktsioonid</translation>
+ </message>
+ </context>
+<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ </context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Amount</source>
+ <translation>Kogus</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Salvesta Pilt...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Kopeeri Pilt</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Salvesta QR Kood</translation>
+ </message>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>&amp;Information</source>
+ <translation>&amp;Informatsioon</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <translation>Üldine</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Võrk</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nimi</translation>
+ </message>
+ <message>
+ <source>Number of connections</source>
+ <translation>Ühenduste arv</translation>
+ </message>
+ <message>
+ <source>Block chain</source>
+ <translation>Blokiahel</translation>
+ </message>
+ <message>
+ <source>Memory usage</source>
+ <translation>Mälu kasutus</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation>Vastu võetud</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation>Saadetud</translation>
+ </message>
+ <message>
+ <source>Direction</source>
+ <translation>Suund</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation>Versioon</translation>
+ </message>
+ <message>
+ <source>Services</source>
+ <translation>Teenused</translation>
+ </message>
+ <message>
+ <source>Ping Time</source>
+ <translation>Pingi Aeg</translation>
+ </message>
+ <message>
+ <source>&amp;Network Traffic</source>
+ <translation>&amp;Võrgu Liiklus</translation>
+ </message>
+ <message>
+ <source>Clear console</source>
+ <translation>Puhasta konsool</translation>
+ </message>
+ <message>
+ <source>never</source>
+ <translation>mitte kunagi</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <translation>Sisenev</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <translation>Väljuv</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Jah</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Ei</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>&amp;Amount:</source>
+ <translation>&amp;Kogus:</translation>
+ </message>
+ <message>
+ <source>&amp;Message:</source>
+ <translation>&amp;Sõnum:</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation>Eemalda</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Kopeeri sõnum</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopeeri kogus</translation>
+ </message>
+</context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>QR Code</source>
+ <translation>QR Kood</translation>
+ </message>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Salvesta Pilt...</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Aadress</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kogus</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Silt</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Sõnum</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Kuupäev</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Silt</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Sõnum</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(silt puudub)</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>Amount:</source>
+ <translation>Kogus</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Vali...</translation>
+ </message>
+ <message>
+ <source>normal</source>
+ <translation>normaalne</translation>
+ </message>
+ <message>
+ <source>fast</source>
+ <translation>kiire</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopeeri kogus</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(silt puudub)</translation>
+ </message>
+</context>
+<context>
+ <name>SendCoinsEntry</name>
+ <message>
+ <source>Alt+A</source>
+ <translation>Alt+A</translation>
+ </message>
+ <message>
+ <source>Alt+P</source>
+ <translation>Alt+P</translation>
+ </message>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Jah</translation>
+ </message>
+</context>
+<context>
+ <name>ShutdownWindow</name>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ <message>
+ <source>Alt+A</source>
+ <translation>Alt+A</translation>
+ </message>
+ <message>
+ <source>Alt+P</source>
+ <translation>Alt+P</translation>
+ </message>
+ <message>
+ <source>Signature</source>
+ <translation>Allkiri</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Palun kontrolli aadressi ja proovi uuesti.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Sõnum allkirjastatud.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Allkirja ei õnnestunud dekodeerida.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Palun kontrolli allkirja ja proovi uuesti.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Sõnumi verifitseerimine ebaõnnestus.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Sõnum verifitseeritud.</translation>
+ </message>
+</context>
+<context>
+ <name>SplashScreen</name>
+ <message>
+ <source>[testnet]</source>
+ <translation>[test võrk]</translation>
+ </message>
+</context>
+<context>
+ <name>TrafficGraphWidget</name>
+ <message>
+ <source>KB/s</source>
+ <translation>KB/s</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Status</source>
+ <translation>Olek</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Kuupäev</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Sõnum</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Kommentaar</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>Transaktsiooni ID</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kogus</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionDescDialog</name>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Kuupäev</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tüüp</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Silt</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(silt puudub)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Kõik</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Täna</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Käimasolev kuu</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Eelmine kuu</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Käimasolev aasta</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Vahemik...</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopeeri aadress</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopeeri summa</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopeeri transaktsiooni ID</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Kinnitatud</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Kuupäev</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tüüp</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Silt</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Aadress</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Vahemik:</translation>
+ </message>
+ </context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Varunda Rahakott</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Rahakoti Andmed (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Varundamine Ebaõnnestus</translation>
+ </message>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Options:</source>
+ <translation>Valikud:</translation>
+ </message>
+ <message>
+ <source>Bitcoin Core</source>
+ <translation>Bitcoin Core</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Informatsioon</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Hoiatus</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Viga</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_eu_ES.ts b/src/qt/locale/bitcoin_eu_ES.ts
index cbe246f443..f7912f0785 100644
--- a/src/qt/locale/bitcoin_eu_ES.ts
+++ b/src/qt/locale/bitcoin_eu_ES.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Ezabatu</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Aukeratu helbidea txanponak bidaltzeko</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Aukeratu helbidea txanponak jasotzeko</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Aukeratu</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Helbideak bidaltzen</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Helbideak jasotzen</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>Hauek dira zure Bitcoin helbideak dirua bidaltzeko. Beti egiaztatu diru-kantitatea eta jasotzeko helbidea bidali baino lehen.</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>Hauek dira zure Bitcoin helbideak dirua jasotzeko. Gomendagarria da erabiltzea jasotzeko helbide berri bat operazio bakoitzeko.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopiatu helbidea</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopiatu &amp;Etiketa</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Editatu</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Esportatu helbide lista</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Komaz bereizitako artxiboa (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Esportatua okerra</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Errakuntza bat egon da gordetzen %1 helbide listan. Mesedez, saiatu berriro.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiketa</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Helbidea</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(etiketarik ez)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,7 +131,75 @@
<source>Repeat new passphrase</source>
<translation>Errepikatu pasahitz berria</translation>
</message>
-</context>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Enkriptatu zorroa</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Eragiketa honek zorroaren pasahitza behar du zorroa desblokeatzeko.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Desblokeatu zorroa</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Eragiketa honek zure zorroaren pasahitza behar du, zorroa desenkriptatzeko.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Desenkriptatu zorroa</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Aldatu pasahitza</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Berretsi zorroaren enkriptazioa</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>Abisua: Zuk enkriptatzen baduzu zure diruzorroa eta zure pasahitza galtzen baduzu, &lt;b&gt;BITCOIN GUZTIAK GALDUKO DITUZU&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Seguru zaude nahi duzula zure diruzorroa enkriptatu?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Zorroa enkriptatuta</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>GARRANTZITSUA: Aurreko seguritate-kopiak ordeztuko dire berriekin, enkriptatutak. Segurtasun arrazoigaitik, aurreko kopiak ezin dira erabili hasiko zarenean zure diruzorro enkriptatu berriarekin.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Zorroaren enkriptazioak huts egin du</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Zorroaren enkriptazioak huts egin du barne-errore baten ondorioz. Zure zorroa ez da enkriptatu.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Eman dituzun pasahitzak ez datoz bat.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Zorroaren desblokeoak huts egin du</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Zorroa desenkriptatzeko sartutako pasahitza okerra da.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Zorroaren desenkriptazioak huts egin du</translation>
+ </message>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -154,7 +293,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Zorroa &lt;b&gt;enkriptatuta&lt;/b&gt; eta &lt;b&gt;blokeatuta&lt;/b&gt; dago une honetan</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -169,6 +308,18 @@
<source>Date</source>
<translation>Data</translation>
</message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopiatu helbidea</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiatu etiketa</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(etiketarik ez)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -184,6 +335,34 @@
<source>&amp;Address</source>
<translation>&amp;Helbidea</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Jasotzeko helbide berria</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Bidaltzeko helbide berria</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Editatu jasotzeko helbidea</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Editatu bidaltzeko helbidea</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Sartu berri den helbidea, "%1", helbide-liburuan dago jadanik.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Ezin desblokeatu zorroa.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Gako berriaren sorrerak huts egin du.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -195,6 +374,13 @@
<name>Intro</name>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Inprimakia</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -212,6 +398,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -222,6 +411,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -238,6 +433,10 @@
<source>&amp;Message:</source>
<translation>Mezua</translation>
</message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiatu etiketa</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -245,6 +444,41 @@
<source>Copy &amp;Address</source>
<translation>&amp;Kopiatu helbidea</translation>
</message>
+ <message>
+ <source>Address</source>
+ <translation>Helbidea</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kopurua</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiketa</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mezua</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiketa</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mezua</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(etiketarik ez)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -268,7 +502,19 @@
<source>Confirm the send action</source>
<translation>Berretsi bidaltzeko ekintza</translation>
</message>
- </context>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Berretsi txanponak bidaltzea</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Ordaintzeko kopurua 0 baino handiagoa izan behar du.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(etiketarik ez)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -303,6 +549,13 @@
<source>Pay To:</source>
<translation>Ordaindu honi:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Sartu etiketa bat helbide honetarako, eta gehitu zure helbide-liburuan</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
</context>
<context>
<name>ShutdownWindow</name>
@@ -333,16 +586,238 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Open until %1</source>
+ <translation>Zabalik %1 arte</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/konfirmatu gabe</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 konfirmazioak</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, ez da arrakastaz emititu oraindik</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>ezezaguna</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mezua</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transakzioaren</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kopurua</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Panel honek transakzioaren deskribapen xehea erakusten du</translation>
</message>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Mota</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiketa</translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Zabalik %1 arte</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Konfirmatuta (%1 konfirmazio)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Bloke hau ez du beste inongo nodorik jaso, eta seguruenik ez da onartuko!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Sortua, baina ez onartua</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Jasota honekin: </translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Hona bidalia: </translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Ordainketa zeure buruari</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Bildua</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/a)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(etiketarik ez)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Transakzioaren egoera. Pasatu sagua gainetik konfirmazio kopurua ikusteko.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Transakzioa jasotako data eta ordua.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Transakzio mota.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Saldoan kendu edo gehitutako kopurua.</translation>
+ </message>
</context>
<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Denak</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Gaur</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Aste honetan</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Hil honetan</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Azken hilean</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Aurten</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Muga...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Jasota honekin: </translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Hona bidalia: </translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Zeure buruari</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Bildua</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Beste</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Sartu bilatzeko helbide edo etiketa</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Kopuru minimoa</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopiatu helbidea</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiatu etiketa</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Komaz bereizitako artxiboa (*.csv)</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Mota</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiketa</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Helbidea</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Esportatua okerra</translation>
+ </message>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Bidali txanponak</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Esportatu</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Esportatu datuak uneko fitxategian</translation>
+ </message>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts
index 98543ded46..c9cfad0f2a 100644
--- a/src/qt/locale/bitcoin_fa.ts
+++ b/src/qt/locale/bitcoin_fa.ts
@@ -41,6 +41,49 @@
<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>انتخاب</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>آدرس های فرستنده</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>آدرس های گیرنده</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>کپی و برچسب‌&amp;گذاری</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;ویرایش</translation>
+ </message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <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>
@@ -60,6 +103,54 @@
<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>Confirm wallet encryption</source>
+ <translation>تأیید رمزنگاری کیف پول</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>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>Wallet unlock failed</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>
@@ -131,6 +222,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>
@@ -235,6 +330,10 @@
<translation>نوارابزار برگه‌ها</translation>
</message>
<message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation>درخواست پرداخت ( تولید کد کیوار و ادرس بیت کوین)</translation>
+ </message>
+ <message>
<source>Show the list of used sending addresses and labels</source>
<translation>نمایش لیست آدرس های ارسال و لیبل ها</translation>
</message>
@@ -243,6 +342,10 @@
<translation>نمایش لیست آدرس های دریافت و لیبل ها</translation>
</message>
<message>
+ <source>Open a bitcoin: URI or payment request</source>
+ <translation>بازکردن یک بیت کوین: آدرس یا درخواست پرداخت</translation>
+ </message>
+ <message>
<source>&amp;Command-line options</source>
<translation>گزینه‌های خط‌فرمان</translation>
</message>
@@ -251,28 +354,12 @@
<translation><numerusform>%n ارتباط فعال با شبکهٔ بیت‌کوین</numerusform></translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>منبعی برای دریافت بلاک در دسترس نیست...</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>
+ <source>Processing blocks on disk...</source>
+ <translation>پردازش بلوک‌ها روی دیسک...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n سال</numerusform></translation>
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>پردازش %n بلاک از تاریخچه ی تراکنش ها </numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -352,7 +439,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -372,10 +459,6 @@
<translation>مبلغ:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>اولویت:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>هزینه:</translation>
</message>
@@ -424,8 +507,48 @@
<translation>تأیید شده</translation>
</message>
<message>
- <source>Priority</source>
- <translation>اولویت</translation>
+ <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>(%1 locked)</source>
+ <translation>(%1 قفل شده)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>بله</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>خیر</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(بدون برچسب)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(تغییر)</translation>
</message>
</context>
<context>
@@ -442,7 +565,35 @@
<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>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -473,6 +624,10 @@
<translation>نسخه</translation>
</message>
<message>
+ <source>(%1-bit)</source>
+ <translation>(%1-بیت)</translation>
+ </message>
+ <message>
<source>About %1</source>
<translation>درباره %1</translation>
</message>
@@ -488,6 +643,26 @@
<source>command-line options</source>
<translation>گزینه‌های خط فرمان</translation>
</message>
+ <message>
+ <source>UI Options:</source>
+ <translation>گزینه‌های رابط کاربری:</translation>
+ </message>
+ <message>
+ <source>Set language, for example "de_DE" (default: system locale)</source>
+ <translation>زبان را تنظیم کنید؛ برای مثال «de_DE» (پیشفرض: زبان سیستم)</translation>
+ </message>
+ <message>
+ <source>Start minimized</source>
+ <translation>شروع برنامه به صورت کوچک‌شده</translation>
+ </message>
+ <message>
+ <source>Set SSL root certificates for payment request (default: -system-)</source>
+ <translation>تنظیم گواهی ریشه SSl برای درخواست پرداخت (پیشفرض: -system-)</translation>
+ </message>
+ <message>
+ <source>Show splash screen on startup (default: %u)</source>
+ <translation>نمایش پنجرهٔ خوشامدگویی در ابتدای اجرای برنامه (پیش‌فرض: %u)</translation>
+ </message>
</context>
<context>
<name>Intro</name>
@@ -517,11 +692,38 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>فرم</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>زمان آخرین بلوک</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>پنهان کردن</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
<translation>بازکردن آدرس</translation>
</message>
+ <message>
+ <source>Open payment request from URI or file</source>
+ <translation>بازکردن درخواست پرداخت از آدرس یا فایل</translation>
+ </message>
+ <message>
+ <source>URI:</source>
+ <translation>آدرس اینترنتی:</translation>
+ </message>
+ <message>
+ <source>Select payment request file</source>
+ <translation>انتخاب فایل درخواست پرداخت</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -534,6 +736,14 @@
<translation>&amp;عمومی</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>اجرای خودکار %1 بعد زمان ورود به سیستم.</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <translation>مگابایت</translation>
+ </message>
+ <message>
<source>Accept connections from outside</source>
<translation>پذیرش اتصالات از بیرون</translation>
</message>
@@ -673,6 +883,10 @@
<translation>تراز علی‌الحساب شما</translation>
</message>
<message>
+ <source>Pending:</source>
+ <translation>در انتظار:</translation>
+ </message>
+ <message>
<source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
<translation>مجموع تراکنش‌هایی که هنوز تأیید نشده‌اند؛ و هنوز روی تراز علی‌الحساب اعمال نشده‌اند</translation>
</message>
@@ -706,12 +920,11 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
- <message>
- <source>Ping Time</source>
- <translation>زمان پینگ</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -719,6 +932,10 @@
<translation>مبلغ</translation>
</message>
<message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation>یک آدرس بیت‌کوین وارد کنید (مثلاً %1)</translation>
+ </message>
+ <message>
<source>%1 d</source>
<translation>%1 روز</translation>
</message>
@@ -746,7 +963,17 @@
<source>%1 ms</source>
<translation>%1 میلیونم ثانیه</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 و %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -794,6 +1021,10 @@
<translation>تعداد فعلی بلوک‌ها</translation>
</message>
<message>
+ <source>Memory Pool</source>
+ <translation>استخر حافظه</translation>
+ </message>
+ <message>
<source>Memory usage</source>
<translation>مصرف حافظه</translation>
</message>
@@ -814,6 +1045,14 @@
<translation>سرویس ها</translation>
</message>
<message>
+ <source>Connection Time</source>
+ <translation>مدت اتصال</translation>
+ </message>
+ <message>
+ <source>Last Send</source>
+ <translation>ارسال شده آخرین بار</translation>
+ </message>
+ <message>
<source>Last Receive</source>
<translation>آخرین دریافتی</translation>
</message>
@@ -909,6 +1148,14 @@
<translation>پیام:</translation>
</message>
<message>
+ <source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
+ <translation>برای درخواست پرداخت از این فرم استفاده کنید.تمام قسمت ها &lt;b&gt;اختیاری&lt;b&gt; هستند.</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation>تمام قسمت های فرم را خالی کن.</translation>
+ </message>
+ <message>
<source>Clear</source>
<translation>پاک‌کردن</translation>
</message>
@@ -917,9 +1164,21 @@
<translation>نمایش</translation>
</message>
<message>
+ <source>Remove the selected entries from the list</source>
+ <translation>حذف ورودی های انتخاب‌شده از لیست</translation>
+ </message>
+ <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>
@@ -935,7 +1194,26 @@
<source>&amp;Save Image...</source>
<translation>&amp;ذخیره عکس...</translation>
</message>
-</context>
+ <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>
<message>
@@ -943,6 +1221,14 @@
<translation>ارسال سکه</translation>
</message>
<message>
+ <source>Inputs...</source>
+ <translation>ورودی‌ها...</translation>
+ </message>
+ <message>
+ <source>automatically selected</source>
+ <translation>به طور خودکار انتخاب شدند</translation>
+ </message>
+ <message>
<source>Insufficient funds!</source>
<translation>بود جه نا کافی </translation>
</message>
@@ -959,10 +1245,6 @@
<translation>مبلغ:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>اولویت:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>هزینه:</translation>
</message>
@@ -979,10 +1261,22 @@
<translation>هزینهٔ تراکنش:</translation>
</message>
<message>
+ <source>Choose...</source>
+ <translation>انتخاب...</translation>
+ </message>
+ <message>
+ <source>per kilobyte</source>
+ <translation>در هر کیلوبایت</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>پنهان کردن</translation>
</message>
<message>
+ <source>total at least</source>
+ <translation>در مجموع حداقل</translation>
+ </message>
+ <message>
<source>Recommended:</source>
<translation>توصیه شده:</translation>
</message>
@@ -991,10 +1285,6 @@
<translation>سفارشی:</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>روز تایید:</translation>
- </message>
- <message>
<source>normal</source>
<translation>نرمال</translation>
</message>
@@ -1011,6 +1301,10 @@
<translation>&amp;دریافت‌کنندهٔ جدید</translation>
</message>
<message>
+ <source>Clear all fields of the form.</source>
+ <translation>تمام قسمت های فرم را خالی کن.</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>پاکسازی &amp;همه</translation>
</message>
@@ -1026,6 +1320,18 @@
<source>S&amp;end</source>
<translation>&amp;ارسال</translation>
</message>
+ <message>
+ <source>Copy quantity</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>
@@ -1081,7 +1387,10 @@
<source>Memo:</source>
<translation>یادداشت:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1167,7 +1476,7 @@
<source>Reset all verify message fields</source>
<translation>بازنشانی تمام فیلدهای پیام</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1183,16 +1492,62 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>این پانل شامل توصیف کاملی از جزئیات تراکنش است</translation>
</message>
-</context>
+ </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 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>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1219,10 +1574,6 @@
<translation>اجرا در پشت زمینه به‌صورت یک سرویس و پذیرش دستورات</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>پذیرش اتصالات از بیرون (پیش فرض:1 بدون پراکسی یا اتصال)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation> هسته Bitcoin </translation>
</message>
@@ -1235,18 +1586,10 @@
<translation>هنگامی که یک تراکنش در کیف پولی رخ می دهد، دستور را اجرا کن(%s در دستورات بوسیله ی TxID جایگزین می شود)</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>Block creation options:</source>
<translation>بستن گزینه ایجاد</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>تنها در گره (های) مشخص شده متصل شوید</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>گزینه‌های اتصال:</translation>
</message>
@@ -1335,10 +1678,6 @@
<translation>مقدار تراکنش بسیار کم است</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>مقادیر تراکنش باید مثبت باشد</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>تراکنش بسیار بزرگ است</translation>
</message>
@@ -1371,6 +1710,10 @@
<translation>بار گیری آدرس ها</translation>
</message>
<message>
+ <source>(default: %s)</source>
+ <translation>(پیش‌فرض %s)</translation>
+ </message>
+ <message>
<source>Invalid -proxy address: '%s'</source>
<translation>آدرس پراکسی اشتباه %s</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts
index 8faa3ce659..1e829aff9e 100644
--- a/src/qt/locale/bitcoin_fa_IR.ts
+++ b/src/qt/locale/bitcoin_fa_IR.ts
@@ -37,7 +37,10 @@
<source>&amp;Delete</source>
<translation>حذف</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -56,7 +59,7 @@
<source>Repeat new passphrase</source>
<translation>رمز/پَس فرِیز را دوباره وارد کنید</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -190,7 +193,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>wallet رمزگذاری شد و در حال حاضر قفل است</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -224,7 +227,7 @@
<source>&amp;Address</source>
<translation>حساب&amp;</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -247,6 +250,13 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>فرم</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -288,6 +298,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -298,6 +311,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>Client version</source>
@@ -343,6 +362,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -372,7 +394,7 @@
<source>S&amp;end</source>
<translation>و ارسال</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -411,7 +433,10 @@
<source>Memo:</source>
<translation>یادداشت:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -453,16 +478,34 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>این بخش جزئیات تراکنش را نشان می دهد</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -513,10 +556,6 @@
<translation>لود شدن آدرسها..</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>تنظیم کمینه اندازه بلاک بر حسب بایت (پیش فرض: %u)</translation>
- </message>
- <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>تنظیم تعداد ریسمان ها برای سرویس دهی فراخوانی های RPC (پیش فرض: %d)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts
index b7b3115e25..ef76abc098 100644
--- a/src/qt/locale/bitcoin_fi.ts
+++ b/src/qt/locale/bitcoin_fi.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Poista</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Toista uusi tunnuslause</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -115,6 +118,10 @@
<translation>&amp;Tietoja %1</translation>
</message>
<message>
+ <source>Show information about %1</source>
+ <translation>Näytä tietoa aiheesta %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>Tietoja &amp;Qt</translation>
</message>
@@ -127,6 +134,10 @@
<translation>&amp;Asetukset...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Muuta kohteen %1 kokoonpanoasetuksia</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Salaa lompakko...</translation>
</message>
@@ -255,32 +266,16 @@
<translation><numerusform>%n aktiivinen yhteys Bitcoin-verkkoon</numerusform><numerusform>%n aktiivista yhteyttä Bitcoin-verkkoon</numerusform></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>
- </message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n tunti</numerusform><numerusform>%n tuntia</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n päivä</numerusform><numerusform>%n päivää</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n viikko</numerusform><numerusform>%n viikkoa</numerusform></translation>
+ <source>Indexing blocks on disk...</source>
+ <translation>Ladataan lohkoindeksiä...</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 ja %2</translation>
+ <source>Processing blocks on disk...</source>
+ <translation>Käsitellään lohkoja levyllä...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n vuosi</numerusform><numerusform>%n vuotta</numerusform></translation>
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>Prosessoitu %n lohko rahansiirtohistoriasta.</numerusform><numerusform>Prosessoitu %n lohkoa rahansiirtohistoriasta.</numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -311,6 +306,14 @@
<translation>Rahansiirtohistoria on ajan tasalla</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Näytä %1 ohjeet saadaksesi listan mahdollisista Bitcoinin komentorivivalinnoista</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>%1-asiakas</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Saavutetaan verkkoa...</translation>
</message>
@@ -360,7 +363,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -380,10 +383,6 @@
<translation>Määrä:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioriteetti:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Palkkio:</translation>
</message>
@@ -435,11 +434,7 @@
<source>Confirmed</source>
<translation>Vahvistettu</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioriteetti</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -462,7 +457,7 @@
<source>&amp;Address</source>
<translation>&amp;Osoite</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -497,6 +492,10 @@
<translation>(%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>Tietoja %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Komentorivi parametrit</translation>
</message>
@@ -532,7 +531,11 @@
<source>Show splash screen on startup (default: %u)</source>
<translation>Näytä aloitusruutu käynnistyksen yhteydessä (oletus: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Nollaa kaikki graafisen käyttöliittymän kautta tehdyt muutokset</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -540,6 +543,18 @@
<translation>Tervetuloa</translation>
</message>
<message>
+ <source>Welcome to %1.</source>
+ <translation>Tervetuloa %1 pariin.</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>Tämä on ensimmäinen kerta, kun %1 on käynnistetty, joten voit valita data-hakemiston paikan.</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>%1 lataa ja tallentaa kopion Bitcoinin lohkoketjusta. Vähintään %2Gt dataa tullaan tallentamaan tähän hakemistoon, ja tarve kasvaa ajan myötä. Lompakko tullaan myös tallentamaan tähän hakemistoon.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Käytä oletuskansiota</translation>
</message>
@@ -565,6 +580,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Lomake</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Viimeisimmän lohkon aika</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Piilota</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -582,7 +612,7 @@
<source>Select payment request file</source>
<translation>Valitse maksupyynnön tiedosto</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -594,6 +624,14 @@
<translation>&amp;Yleiset</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>Käynnistä %1 automaattisesti järjestelmään kirjautumisen jälkeen.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>&amp;Käynnistä %1 järjestelmään kirjautuessa</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>&amp;Tietokannan välimuistin koko</translation>
</message>
@@ -750,6 +788,10 @@
<translation>&amp;Käyttöliittymän kieli</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>Tässä voit määritellä käyttöliittymän kielen. Muutokset astuvat voimaan seuraavan kerran, kun %1 käynnistetään.</translation>
+ </message>
+ <message>
<source>&amp;Unit to show amounts in:</source>
<translation>Yksikkö jona bitcoin-määrät näytetään</translation>
</message>
@@ -874,6 +916,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -883,11 +928,7 @@
<source>Node/Service</source>
<translation>Noodi/Palvelu</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Vasteaika</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -926,7 +967,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 ja %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -954,6 +1005,10 @@
<translation>Käyttää BerkeleyDB-versiota</translation>
</message>
<message>
+ <source>Datadir</source>
+ <translation>Data-hakemisto</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>Käynnistysaika</translation>
</message>
@@ -1038,6 +1093,18 @@
<translation>Käyttöliittymä</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>Avaa %1 -debug-loki tämänhetkisestä data-hakemistosta. Tämä voi viedä muutaman sekunnin suurille lokitiedostoille.</translation>
+ </message>
+ <message>
+ <source>Decrease font size</source>
+ <translation>Pienennä fontin kokoa</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation>Suurenna fontin kokoa</translation>
+ </message>
+ <message>
<source>Services</source>
<translation>Palvelut</translation>
</message>
@@ -1114,14 +1181,6 @@
<translation>Tyhjennä konsoli</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Katkaise yhteys solmukohtaan</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Estä solmukohta</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;tunti</translation>
</message>
@@ -1138,10 +1197,6 @@
<translation>1 &amp;vuosi</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Poista solmukohdan esto</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>
@@ -1268,7 +1323,7 @@
<source>Remove</source>
<translation>Poista</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1287,7 +1342,14 @@
<source>&amp;Save Image...</source>
<translation>&amp;Tallenna kuva</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Aika</translation>
+ </message>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1323,10 +1385,6 @@
<translation>Määrä:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioriteetti:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Palkkio:</translation>
</message>
@@ -1387,10 +1445,6 @@
<translation>(Älykästä rahansiirtokulua ei ole vielä alustettu. Tähän kuluu yleensä aikaa muutaman lohkon verran...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Vahvistusaika:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normaali</translation>
</message>
@@ -1430,7 +1484,7 @@
<source>S&amp;end</source>
<translation>&amp;Lähetä</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1474,6 +1528,10 @@
<translation>Poista tämä alkio</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>Kulu vähennetään lähetettävästä määrästä. Saaja vastaanottaa vähemmän bitcoineja kuin merkitset Määrä-kenttään. Jos saajia on monia, kulu jaetaan tasan.</translation>
+ </message>
+ <message>
<source>S&amp;ubtract fee from amount</source>
<translation>V&amp;ähennä maksukulu määrästä</translation>
</message>
@@ -1505,10 +1563,17 @@
<source>Memo:</source>
<translation>Muistio:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down...</source>
+ <translation>%1 sulkeutuu...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation>Älä sammuta tietokonetta ennenkuin tämä ikkuna katoaa.</translation>
</message>
@@ -1591,7 +1656,7 @@
<source>Reset all verify message fields</source>
<translation>Tyhjennä kaikki varmista-viesti-kentät</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1607,12 +1672,33 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation>Aika</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Tämä ruutu näyttää yksityiskohtaisen tiedon rahansiirrosta</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Aika</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Date</source>
+ <translation>Aika</translation>
+ </message>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1621,6 +1707,19 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Vie</translation>
+ </message>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1655,10 +1754,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>
@@ -1683,48 +1778,52 @@
<translation>HTTP-palvelinta ei voitu käynnistää. Katso debug-lokista lisätietoja.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Hyväksy yhteyksiä ulkopuolelta (vakioasetus: 1 jos -proxy tai -connect ei määritelty)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin-ydin</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee on asetettu erittäin suureksi! Tämä on rahansiirtokulu jonka voit maksaa kun arvioitu rahansirtokulu ei ole saatavilla.</translation>
+ <source>The %s developers</source>
+ <translation>%s kehittäjät</translation>
</message>
<message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
<translation>Kytkeydy annettuun osoitteeseen ja pidä linja aina auki. Käytä [host]:portin merkintätapaa IPv6:lle.</translation>
</message>
<message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation>Ei voida lukita data-hakemistoa %s. %s on luultavasti jo käynnissä.</translation>
+ </message>
+ <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Suorita käsky kun lompakossa rahansiirto muuttuu (%s cmd on vaihdettu TxID kanssa)</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>
+ <translation>Tarkistathan että tietokoneesi päivämäärä ja kellonaika ovat oikeassa! Jos kellosi on väärässä, %s ei toimi oikein.</translation>
+ </message>
+ <message>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
+ <translation>Ole hyvä ja avusta, jos %s on mielestäsi hyödyllinen. Vieraile %s saadaksesi lisää tietoa ohjelmistosta.</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>Aseta script varmistuksen threadien lukumäärä (%u - %d, 0= auto, &lt;0 = jätä näin monta ydintä vapaaksi, oletus: %d)</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>Tämä on esi-julkaistu testiversio - Käytä omalla riskillä - Ei saa käytää louhimiseen tai kauppasovelluksiin.</translation>
+ <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>Lohkotietokanta sisältää lohkon, joka vaikuttaa olevan tulevaisuudesta. Tämä saattaa johtua tietokoneesi virheellisesti asetetuista aika-asetuksista. Rakenna lohkotietokanta uudelleen vain jos olet varma, että tietokoneesi päivämäärä ja aika ovat oikein.</translation>
</message>
<message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<translation>Käytä UPnP:ta kuuntelevan portin kartoitukseen (oletus: 1 kun kuunnellaan ja -proxy ei käytössä)</translation>
</message>
<message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Varoitus: Tietoverkko ei ole sovussa! Luohijat näyttävät kokevan virhetilanteita.</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>Varoitus: Olemme vertaisverkon kanssa ristiriidassa! Sinun tulee päivittää tai toisten solmujen tulee päivitää.</translation>
+ <source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
+ <translation>Sinun tulee uudelleenrakentaa tietokanta käyttäen -reindex-chainstate vaihtaaksesi -txindex</translation>
</message>
<message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Salli vertaisten yhdistää annetusta verkkomaskista tai IP-osoitteesta. Voidaan määrittää useampia kertoja.</translation>
+ <source>%s corrupt, salvage failed</source>
+ <translation>%s korruptoitunut, korjaaminen epäonnistui</translation>
</message>
<message>
<source>-maxmempool must be at least %d MB</source>
@@ -1735,18 +1834,26 @@
<translation>&lt;category&gt; voi olla:</translation>
</message>
<message>
+ <source>Attempt to recover private keys from a corrupt wallet on startup</source>
+ <translation>Yritä palauttaa yksityiset avaimet korruptoituneesta lompakosta käynnistyksen yhteydessä</translation>
+ </message>
+ <message>
<source>Block creation options:</source>
<translation>Lohkon luonnin asetukset:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Yhidstä ainoastaan määrättyihin noodeihin</translation>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>-%s -osoitteen '%s' selvittäminen epäonnistui</translation>
</message>
<message>
<source>Connection options:</source>
<translation>Yhteyden valinnat:</translation>
</message>
<message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Tekijänoikeus (C) %i-%i</translation>
+ </message>
+ <message>
<source>Corrupted block database detected</source>
<translation>Vioittunut lohkotietokanta havaittu</translation>
</message>
@@ -1775,6 +1882,18 @@
<translation>Virhe alustaessa lompakon tietokantaympäristöä %s!</translation>
</message>
<message>
+ <source>Error loading %s</source>
+ <translation>Virhe ladattaessa %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation>Virhe ladattaessa %s: Lompakko vioittunut</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation>Virhe ladattaessa %s: Tarvitset uudemman %s -version</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>Virhe avattaessa lohkoketjua</translation>
</message>
@@ -1803,6 +1922,22 @@
<translation>Virheellinen -onion osoite: '%s'</translation>
</message>
<message>
+ <source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
+ <translation>Virheellinen määrä -%s=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
+ <translation>Virheellinen määrä -fallbackfee=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
+ <source>Loading banlist...</source>
+ <translation>Ladataan kieltolistaa...</translation>
+ </message>
+ <message>
+ <source>Location of the auth cookie (default: data dir)</source>
+ <translation>Todennusevästeen sijainti (oletus: datahakemisto)</translation>
+ </message>
+ <message>
<source>Not enough file descriptors available.</source>
<translation>Ei tarpeeksi tiedostomerkintöjä vapaana.</translation>
</message>
@@ -1811,6 +1946,14 @@
<translation>Yhdistä vain solmukohtiin &lt;net&gt;-verkossa (ipv4, ipv6 tai onion)</translation>
</message>
<message>
+ <source>Print this help message and exit</source>
+ <translation>Näytä tämä ohjeviesti ja poistu</translation>
+ </message>
+ <message>
+ <source>Print version and exit</source>
+ <translation>Näytä versio ja poistu.</translation>
+ </message>
+ <message>
<source>Prune mode is incompatible with -txindex.</source>
<translation>Karsittu tila ei ole yhteensopiva -txindex:n kanssa.</translation>
</message>
@@ -1827,6 +1970,22 @@
<translation>Aseta lompakkotiedosto (data-hakemiston sisällä)</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation>Lähdekoodi löytyy %s.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
+ <translation>Argumenttia -benchmark ei tueta, käytä -debug=bench.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -debugnet ignored, use -debug=net.</source>
+ <translation>Argumenttia -debugnet ei tueta, käytä -debug=net.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -tor found, use -onion.</source>
+ <translation>Argumenttia -tor ei tueta, käytä -onion.</translation>
+ </message>
+ <message>
<source>Use UPnP to map the listening port (default: %u)</source>
<translation>Käytä UPnP:ta kuuntelevan portin kartoittamiseen (oletus: %u)</translation>
</message>
@@ -1843,6 +2002,10 @@
<translation>Lompakko %s sijaitsee data-hakemiston ulkopuolella %s</translation>
</message>
<message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>Lompakko tarvitsee uudelleenkirjoittaa: käynnistä %s uudelleen</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Lompakon valinnat:</translation>
</message>
@@ -1855,6 +2018,10 @@
<translation>Paljasta omat IP-osoitteet (oletus: 1 kun kuunnellaan ja -externalip tai -proxy ei ole käytössä)</translation>
</message>
<message>
+ <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
+ <translation>Virhe: Saapuvien yhteyksien kuuntelu epäonnistui (kuuntelu palautti virheen %s)</translation>
+ </message>
+ <message>
<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>Aja komento kun olennainen hälytys vastaanotetaan tai nähdään todella pitkä haara (%s komennossa korvataan viestillä)</translation>
</message>
@@ -1863,6 +2030,10 @@
<translation>Aseta maksimikoko korkea prioriteetti/pieni palkkio rahansiirtoihin tavuissa (oletus: %d)</translation>
</message>
<message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation>Siirtomäärä on liian pieni lähetettäväksi kulun vähentämisen jälkeen.</translation>
+ </message>
+ <message>
<source>(default: %u)</source>
<translation>(oletus: %u)</translation>
</message>
@@ -1871,6 +2042,10 @@
<translation>Hyväksy julkisia REST-pyyntöjä (oletus: %u)</translation>
</message>
<message>
+ <source>Automatically create Tor hidden service (default: %d)</source>
+ <translation>Luo Tor-salattu palvelu automaattisesti (oletus: %d)</translation>
+ </message>
+ <message>
<source>Connect through SOCKS5 proxy</source>
<translation>Yhdistä SOCKS5 proxin kautta</translation>
</message>
@@ -1879,14 +2054,30 @@
<translation>Virheitä tietokantaa luettaessa, ohjelma pysäytetään.</translation>
</message>
<message>
+ <source>Imports blocks from external blk000??.dat file on startup</source>
+ <translation>Tuo lohkot ulkoisesta blk000??.dat -tiedostosta käynnistettäessä</translation>
+ </message>
+ <message>
<source>Information</source>
<translation>Tietoa</translation>
</message>
<message>
+ <source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
+ <translation>Kelvoton määrä argumentille -paytxfee=&lt;amount&gt;: '%s' (pitää olla vähintään %s)</translation>
+ </message>
+ <message>
+ <source>Invalid netmask specified in -whitelist: '%s'</source>
+ <translation>Kelvoton verkkopeite määritelty argumentissa -whitelist: '%s'</translation>
+ </message>
+ <message>
<source>Keep at most &lt;n&gt; unconnectable transactions in memory (default: %u)</source>
<translation>Pidä enimmillään &lt;n&gt; yhdistämiskelvotonta rahansiirtoa muistissa (oletus: %u)</translation>
</message>
<message>
+ <source>Need to specify a port with -whitebind: '%s'</source>
+ <translation>Pitää määritellä portti argumentilla -whitebind: '%s'</translation>
+ </message>
+ <message>
<source>Node relay options:</source>
<translation>Välityssolmukohdan asetukset:</translation>
</message>
@@ -1935,10 +2126,6 @@
<translation>Siirtosumma liian pieni</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Siirtosumman tulee olla positiivinen</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Rahansiirto on liian suuri maksukulukäytännölle</translation>
</message>
@@ -1991,10 +2178,6 @@
<translation>-maxtxfee on asetettu erittäin suureksi! Tämänkokoisia kuluja saatetaan maksaa yhdessä rahansiirrossa.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee on asetettu erittäin suureksi! Tämä on rahansiirtokulu, jonka maksat, mikäli lähetät rahansiirron.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Älä pidä rahansiirtoja muistivarannoissa kauemmin kuin &lt;n&gt; tuntia (oletus: %u)</translation>
</message>
@@ -2003,6 +2186,10 @@
<translation>Kuinka läpikäyvä lohkojen -checkblocks -todennus on (0-4, oletus: %u)</translation>
</message>
<message>
+ <source>Output debugging information (default: %u, supplying &lt;category&gt; is optional)</source>
+ <translation>Tulosta debuggaustieto (oletus: %u, annettu &lt;category&gt; valinnainen)</translation>
+ </message>
+ <message>
<source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)</source>
<translation>Käytä erillistä SOCKS5-proxyä tavoittaaksesi vertaisia Tor-piilopalveluiden kautta (oletus: %s)</translation>
</message>
@@ -2067,8 +2254,8 @@
<translation>Aseta avainaltaan kooksi &lt;n&gt; (oletus: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Aseta pienin mahdollinen lohkokoko tavuina (oletus: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Aseta suurin BIP141-lohkopaino (oletus: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts
index 0b538d7664..2180023159 100644
--- a/src/qt/locale/bitcoin_fr.ts
+++ b/src/qt/locale/bitcoin_fr.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Supprimer</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Choisir l'adresse à laquelle envoyer des pièces</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Choisir l'adresse avec laquelle recevoir des pîèces</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>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>Voici vos adresses Bitcoin pour envoyer des paiements. Vérifiez toujours le montant et l'adresse du destinataire avant d'envoyer des pièces.</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>Voici vos adresses Bitcoin pour recevoir des paiements. Il est recommandé d'utiliser une nouvelle adresse de réception pour chaque transaction.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Copier l'adresse</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copier l'é&amp;tiquette</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Modifier</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 d'exportation</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Une erreur est survenue lors de l'enregistrement de la liste d'adresses vers %1. Veuillez ressayer plus tard.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <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>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>Répéter la phrase de passe</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>Saisissez la nouvelle phrase de passe du porte-monnaie.&lt;br/&gt;Veuillez utiliser une phrase de passe composée de &lt;b&gt;dix caractères aléatoires ou plus&lt;/b&gt;, ou de &lt;b&gt;huit mots ou plus&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Chiffrer le porte-monnaie</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Cette opération nécessite votre phrase de passe pour déverrouiller le porte-monnaie.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Déverrouiller le porte-monnaie</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Cette opération nécessite votre phrase de passe pour déchiffrer le porte-monnaie.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Déchiffrer le porte-monnaie</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Changer la phrase de passe</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Saisir l'ancienne puis la nouvelle phrase de passe du porte-monnaie.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Confirmer le chiffrement du 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>Avertissement : si vous chiffrez votre porte-monnaie et perdez votre phrase de passe, vous &lt;b&gt;PERDREZ TOUS VOS BITCOINS&lt;/b&gt; !</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Voulez-vous vraiment chiffrer votre porte-monnaie ?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Le porte-monnaie est chiffré</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 va maintenant se fermer pour terminer le processus de chiffrement. Souvenez-vous que le chiffrement de votre porte-monnaie ne peut pas protéger entièrement vos bitcoins contre le vol par des logiciels malveillants qui infecteraient votre ordinateur.</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>IMPORTANT : toutes les sauvegardes précédentes du fichier de votre porte-monnaie devraient être remplacées par le fichier du porte-monnaie chiffré nouvellement généré. Pour des raisons de sécurité, les sauvegardes précédentes de votre fichier de porte-monnaie non chiffré deviendront inutilisables dès que vous commencerez à utiliser le nouveau porte-monnaie chiffré.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Échec de chiffrement du porte-monnaie</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Le chiffrement du porte-monnaie a échoué en raison d'une erreur interne. Votre porte-monnaie n'a pas été chiffré.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Les phrases de passe saisies ne correspondent pas.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Échec de déverrouillage du porte-monnaie</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>La phrase de passe saisie pour déchiffrer le porte-monnaie était erronée.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Échec de déchiffrement du porte-monnaie</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>La phrase de passe du porte-monnaie a été modifiée avec succès.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Avertissement : la touche Verr. Maj. est activée !</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -76,11 +235,11 @@
<name>BitcoinGUI</name>
<message>
<source>Sign &amp;message...</source>
- <translation>&amp;Signer le message...</translation>
+ <translation>Signer un &amp;message...</translation>
</message>
<message>
<source>Synchronizing with network...</source>
- <translation>Synchronisation avec le réseau en cours…</translation>
+ <translation>Synchronisation avec le réseau…</translation>
</message>
<message>
<source>&amp;Overview</source>
@@ -100,7 +259,7 @@
</message>
<message>
<source>Browse transaction history</source>
- <translation>Parcourir l'historique des transactions</translation>
+ <translation>Parcourir l'historique transactionnel</translation>
</message>
<message>
<source>E&amp;xit</source>
@@ -156,7 +315,23 @@
</message>
<message>
<source>Open &amp;URI...</source>
- <translation>Ouvrir un &amp;URI...</translation>
+ <translation>Ouvrir une &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Click to disable network activity.</source>
+ <translation>Cliquer pour désactiver l'activité réseau.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>L'activité réseau est désactivée.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <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>
@@ -204,15 +379,15 @@
</message>
<message>
<source>&amp;Show / Hide</source>
- <translation>&amp;Afficher / Cacher</translation>
+ <translation>&amp;Afficher / cacher</translation>
</message>
<message>
<source>Show or hide the main Window</source>
- <translation>Afficher ou masquer la fenêtre principale</translation>
+ <translation>Afficher ou cacher la fenêtre principale</translation>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
- <translation>Chiffrer les clefs privées de votre porte-monnaie</translation>
+ <translation>Chiffrer les clés privées qui appartiennent à votre porte-monnaie</translation>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
@@ -220,7 +395,7 @@
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation>Vérifier les messages pour vous assurer qu'ils ont été signés avec les adresses Bitcoin spécifiées</translation>
+ <translation>Vérifier les messages pour s'assurer qu'ils ont été signés avec les adresses Bitcoin spécifiées</translation>
</message>
<message>
<source>&amp;File</source>
@@ -228,7 +403,7 @@
</message>
<message>
<source>&amp;Settings</source>
- <translation>&amp;Réglages</translation>
+ <translation>&amp;Paramètres</translation>
</message>
<message>
<source>&amp;Help</source>
@@ -240,7 +415,7 @@
</message>
<message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation>Demander des paiements (génère des codes QR et des URIs bitcoin:)</translation>
+ <translation>Demander des paiements (génère des codes QR et des URI bitcoin:)</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
@@ -252,7 +427,7 @@
</message>
<message>
<source>Open a bitcoin: URI or payment request</source>
- <translation>Ouvrir un URI bitcoin: ou une demande de paiement</translation>
+ <translation>Ouvrir une URI bitcoin: ou une demande de paiement</translation>
</message>
<message>
<source>&amp;Command-line options</source>
@@ -270,37 +445,13 @@
<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>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n heure</numerusform><numerusform>%n heures</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n jour</numerusform><numerusform>%n jours</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n semaine</numerusform><numerusform>%n semaines</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 et %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n an</numerusform><numerusform>%n ans</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
- <translation>%1 en retard</translation>
+ <translation>en retard de %1</translation>
</message>
<message>
<source>Last received block was generated %1 ago.</source>
@@ -308,7 +459,7 @@
</message>
<message>
<source>Transactions after this will not yet be visible.</source>
- <translation>Les transactions après ceci ne sont pas encore visibles.</translation>
+ <translation>Les transactions suivantes ne seront pas déjà visibles.</translation>
</message>
<message>
<source>Error</source>
@@ -335,8 +486,12 @@
<translation>Client %1</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Connexion aux pairs...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
- <translation>Rattrapage en cours…</translation>
+ <translation>Rattrapage…</translation>
</message>
<message>
<source>Date: %1
@@ -377,6 +532,14 @@
<translation>Transaction entrante</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>La génération de clé HD est &lt;b&gt;activée&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>La génération de clé HD est &lt;b&gt;désactivée&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>Le porte-monnaie est &lt;b&gt;chiffré&lt;/b&gt; et est actuellement &lt;b&gt;déverrouillé&lt;/b&gt;</translation>
</message>
@@ -384,6 +547,10 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Le porte-monnaie est &lt;b&gt;chiffré&lt;/b&gt; et actuellement &lt;b&gt;verrouillé&lt;/b&gt;</translation>
</message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Une erreur fatale est survenue. Bitcoin ne peut plus continuer en toute sécurité et va s'arrêter.</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -404,10 +571,6 @@
<translation>Montant :</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorité :</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Frais :</translation>
</message>
@@ -425,7 +588,7 @@
</message>
<message>
<source>(un)select all</source>
- <translation>Tout (dé)sélectionner</translation>
+ <translation>Tout (des)sélectionner</translation>
</message>
<message>
<source>Tree mode</source>
@@ -460,8 +623,84 @@
<translation>Confirmée</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Priorité</translation>
+ <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 la transaction</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Verrouiller les transactions non dépensées</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Déverrouiller les transactions non dépensées</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>Copy dust</source>
+ <translation>Copier la poussière</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copier la monnaie</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 verrouillée)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>oui</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>non</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Cette étiquette devient rouge si un destinataire reçoit un montant inférieur au seuil actuel de poussière.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Peut varier +/- %1 satoshi(s) par entrée.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(aucune étiquette)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>monnaie de %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(monnaie)</translation>
</message>
</context>
<context>
@@ -472,7 +711,7 @@
</message>
<message>
<source>&amp;Label</source>
- <translation>&amp;Étiquette</translation>
+ <translation>É&amp;tiquette</translation>
</message>
<message>
<source>The label associated with this address list entry</source>
@@ -480,12 +719,44 @@
</message>
<message>
<source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
- <translation>L'adresse associée à cette entrée de la liste d'adresses. Ceci ne peut être modifié que pour les adresses d'envoi.</translation>
+ <translation>L'adresse associée à cette entrée de la liste d'adresses. Cela ne peut être modifié que pour les adresses d'envoi.</translation>
</message>
<message>
<source>&amp;Address</source>
<translation>&amp;Adresse</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nouvelle adresse de réception</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nouvelle adresse d’envoi</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Modifier l’adresse de réception</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Modifier l’adresse d'envoi</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>L'adresse saisie « %1 » n'est pas une adresse Bitcoin valide.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>L’adresse saisie « %1 » est déjà présente dans le carnet d'adresses.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Impossible de déverrouiller le porte-monnaie.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Échec de génération de la nouvelle clé.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -499,7 +770,7 @@
</message>
<message>
<source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
- <translation>Le répertoire existe déjà. Ajoutez %1 si vous voulez créer un nouveau répertoire ici.</translation>
+ <translation>Le répertoire existe déjà. Ajouter %1 si vous comptez créer un nouveau répertoire ici.</translation>
</message>
<message>
<source>Path already exists, and is not a directory.</source>
@@ -605,18 +876,69 @@
</message>
<message numerus="yes">
<source>(of %n GB needed)</source>
- <translation><numerusform>(sur %n Go nécessaire)</numerusform><numerusform>(sur %n Go nécessaires)</numerusform></translation>
+ <translation><numerusform>(sur %n Go requis)</numerusform><numerusform>(sur %n Go requis)</numerusform></translation>
+ </message>
+</context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulaire</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>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>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Toute tentative de dépense de bitcoins affectés par des transactions qui ne sont pas encore affichées ne sera pas acceptée par le réseau.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Nombre de blocs restants</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Inconnu...</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Horodatage du dernier bloc</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>Progression</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Avancement de la progression par heure</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>calcul en cours...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Temps estimé avant la fin de la synchronisation</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Cacher</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Inconnu. Synchronisation des en-têtes (%1)...</translation>
</message>
</context>
<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
- <translation>Ouvrir un URI</translation>
+ <translation>Ouvrir une URI</translation>
</message>
<message>
<source>Open payment request from URI or file</source>
- <translation>Ouvrir une demande de paiement à partir d'un URI ou d'un fichier</translation>
+ <translation>Ouvrir une demande de paiement à partir d'une URI ou d'un fichier</translation>
</message>
<message>
<source>URI:</source>
@@ -626,6 +948,10 @@
<source>Select payment request file</source>
<translation>Choisir le fichier de demande de paiement</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Choisir le fichier de demande de paiement à ouvrir</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -635,7 +961,7 @@
</message>
<message>
<source>&amp;Main</source>
- <translation>Réglages &amp;principaux</translation>
+ <translation>&amp;Principaux</translation>
</message>
<message>
<source>Automatically start %1 after logging in to the system.</source>
@@ -655,7 +981,7 @@
</message>
<message>
<source>Number of script &amp;verification threads</source>
- <translation>Nombre d'exétrons de &amp;vérification de script</translation>
+ <translation>Nombre de fils de &amp;vérification de script</translation>
</message>
<message>
<source>Accept connections from outside</source>
@@ -667,7 +993,7 @@
</message>
<message>
<source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
- <translation>Adresse IP du mandataire (par ex. IPv4 : 127.0.0.1 / IPv6 : ::1)</translation>
+ <translation>Adresse IP du mandataire (p. ex. IPv4 : 127.0.0.1 / IPv6 : ::1)</translation>
</message>
<message>
<source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
@@ -675,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>URL de tiers (par ex. un explorateur de blocs) apparaissant dans l'onglet des transactions comme éléments du menu contextuel. %s dans l'URL est remplacé par le hachage de la transaction. Les URL multiples sont séparées par une barre verticale |.</translation>
+ <translation>URL de tiers (p. ex. un explorateur de blocs) apparaissant dans l'onglet des transactions comme éléments du menu contextuel. %s dans l'URL est remplacé par le hachage de la transaction. Les URL multiples sont séparées par une barre verticale |.</translation>
</message>
<message>
<source>Third party transaction URLs</source>
@@ -691,7 +1017,7 @@
</message>
<message>
<source>&amp;Reset Options</source>
- <translation>&amp;Réinitialisation des options</translation>
+ <translation>&amp;Réinitialiser les options</translation>
</message>
<message>
<source>&amp;Network</source>
@@ -711,11 +1037,11 @@
</message>
<message>
<source>Enable coin &amp;control features</source>
- <translation>Activer les fonctions de &amp;contrôle des pièces </translation>
+ <translation>Activer les fonctions de &amp;contrôle des pièces</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>Si vous désactivé la dépense de la monnaie non confirmée, la monnaie d'une transaction ne peut pas être utilisée tant que cette transaction n'a pas reçu au moins une confirmation. Ceci affecte aussi comment votre solde est calculé.</translation>
+ <translation>Si vous désactivé la dépense de la monnaie non confirmée, la monnaie d'une transaction ne peut pas être utilisée tant que cette transaction n'a pas reçu au moins une confirmation. Celai affecte aussi le calcul de votre solde.</translation>
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
@@ -723,7 +1049,7 @@
</message>
<message>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
- <translation>Ouvrir le port du client Bitcoin automatiquement sur le routeur. Ceci ne fonctionne que si votre routeur supporte l'UPnP et si la fonctionnalité est activée.</translation>
+ <translation>Ouvrir automatiquement le port du client Bitcoin sur le routeur. Cela ne fonctionne que si votre routeur prend en charge l'UPnP et si la fonction est activée.</translation>
</message>
<message>
<source>Map port using &amp;UPnP</source>
@@ -739,7 +1065,7 @@
</message>
<message>
<source>Proxy &amp;IP:</source>
- <translation>&amp;IP du serveur mandataire :</translation>
+ <translation>&amp;IP du mandataire :</translation>
</message>
<message>
<source>&amp;Port:</source>
@@ -747,7 +1073,7 @@
</message>
<message>
<source>Port of the proxy (e.g. 9050)</source>
- <translation>Port du serveur mandataire (par ex. 9050)</translation>
+ <translation>Port du mandataire (p. ex. 9050)</translation>
</message>
<message>
<source>Used for reaching peers via:</source>
@@ -791,11 +1117,11 @@
</message>
<message>
<source>Show only a tray icon after minimizing the window.</source>
- <translation>Afficher uniquement une icône système après minimisation.</translation>
+ <translation>N'afficher qu'une icône dans la zone de notification après minimisation.</translation>
</message>
<message>
<source>&amp;Minimize to the tray instead of the taskbar</source>
- <translation>&amp;Minimiser dans la barre système au lieu de la barre des tâches</translation>
+ <translation>&amp;Minimiser dans la zone de notification au lieu de la barre des tâches</translation>
</message>
<message>
<source>M&amp;inimize on close</source>
@@ -819,7 +1145,7 @@
</message>
<message>
<source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
- <translation>Choisissez la sous-unité par défaut pour l'affichage dans l'interface et lors de l'envoi de pièces.</translation>
+ <translation>Choisir la sous-unité par défaut d'affichage dans l'interface et lors d'envoi de pièces.</translation>
</message>
<message>
<source>Whether to show coin control features or not.</source>
@@ -847,7 +1173,7 @@
</message>
<message>
<source>Client restart required to activate changes.</source>
- <translation>Le redémarrage du client est nécessaire pour activer les changements.</translation>
+ <translation>Le redémarrage du client est exigé pour activer les changements.</translation>
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
@@ -882,7 +1208,7 @@
</message>
<message>
<source>Your current spendable balance</source>
- <translation>Votre solde actuel pouvant être dépensé</translation>
+ <translation>Votre solde actuel disponible</translation>
</message>
<message>
<source>Pending:</source>
@@ -890,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>Total des transactions qui doivent encore être confirmées et qu'il n'est pas encore possible de dépenser</translation>
+ <translation>Total des transactions qui doivent encore être confirmées et qui ne sont pas prises en compte dans le solde disponible</translation>
</message>
<message>
<source>Immature:</source>
@@ -938,6 +1264,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Erreur de demande de paiement</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Impossible de démarrer le gestionnaire de cliquer-pour-payer bitcoin:</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Gestion des URI</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>L'URL de récupération de la demande de paiement est invalide : %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Adresse de paiement invalide %1</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation>L'URI ne peut pas être analysée ! Cela peut être causé par une adresse Bitcoin invalide ou par des paramètres d'URI mal formés.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Gestion des fichiers de demande de paiement</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>Le fichier de demande de paiement ne peut pas être lu ! Cela peut être causé par un fichier de demande de paiement invalide.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Demande de paiement rejetée</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Le réseau de la demande de paiement ne correspond pas au réseau du client.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>La demande de paiement a expiré</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>La demande de paiement n'est pas initialisée.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Les demandes de paiements non vérifiées vers des scripts de paiement personnalisés ne sont pas prises en charge.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Demande de paiement invalide.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Le paiement demandé d'un montant de %1 est trop faible (considéré comme de la poussière).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Remboursement de %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>La demande de paiement %1 est trop grande (%2 octets, %3 octets permis).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Erreur de communication avec %1 : %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>La demande de paiement ne peut pas être analysée !</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Mauvaise réponse du serveur %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Erreur de demande réseau</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Le paiement a été confirmé</translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -948,8 +1365,12 @@
<translation>Nœud/service</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Temps de ping</translation>
+ <source>NodeId</source>
+ <translation>NodeId</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
</message>
</context>
<context>
@@ -990,6 +1411,72 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n seconde</numerusform><numerusform>%n secondes</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minute</numerusform><numerusform>%n minutes</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n heure</numerusform><numerusform>%n heures</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n jour</numerusform><numerusform>%n jours</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n semaine</numerusform><numerusform>%n semaines</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 et %2</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n an</numerusform><numerusform>%n ans</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 ne s'est pas encore arrêté en toute sécurité...</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Erreur : le répertoire de données indiqué « %1 » n'existe pas.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>Erreur : impossible d'analyser le fichier de configuration : %1. N’utiliser que la syntaxe clef=valeur.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Erreur : %1</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Enregistrer l'image...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Copier l'image</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Enregistrer le code QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Image PNG (*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1107,7 +1594,7 @@
</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>Ouvrir le journal de débogage de %1 depuis le répertoire de données actuel. Ceci peut prendre quelques secondes pour les journaux de grande taille.</translation>
+ <translation>Ouvrir le fichier journal de débogage de %1 à partir du répertoire de données actuel. Cela peut prendre quelques secondes pour les fichiers journaux de grande taille.</translation>
</message>
<message>
<source>Decrease font size</source>
@@ -1143,13 +1630,17 @@
</message>
<message>
<source>The duration of a currently outstanding ping.</source>
- <translation>La durée d'un ping actuellement en cours.</translation>
+ <translation>La durée d'un ping en cours.</translation>
</message>
<message>
<source>Ping Wait</source>
<translation>Attente du ping</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Ping min.</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Décalage temporel</translation>
</message>
@@ -1171,7 +1662,7 @@
</message>
<message>
<source>&amp;Clear</source>
- <translation>&amp;Nettoyer</translation>
+ <translation>&amp;Effacer</translation>
</message>
<message>
<source>Totals</source>
@@ -1187,19 +1678,11 @@
</message>
<message>
<source>Debug log file</source>
- <translation>Journal de débogage</translation>
+ <translation>Fichier journal de débogage</translation>
</message>
<message>
<source>Clear console</source>
- <translation>Nettoyer la console</translation>
- </message>
- <message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Déconnecter le nœud</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Bannir le nœud pendant</translation>
+ <translation>Effacer la console</translation>
</message>
<message>
<source>1 &amp;hour</source>
@@ -1218,8 +1701,16 @@
<translation>1 &amp;an</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Réhabiliter le nœud</translation>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Déconnecter</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Bannir pendant</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Réhabiliter</translation>
</message>
<message>
<source>Welcome to the %1 RPC console.</source>
@@ -1227,13 +1718,21 @@
</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>Utiliser les touches de curseur pour naviguer dans l'historique et &lt;b&gt;Ctrl-L&lt;/b&gt; pour effacer l'écran.</translation>
+ <translation>Utiliser les touches de déplacement pour naviguer dans l'historique et &lt;b&gt;Ctrl-L&lt;/b&gt; pour effacer l'écran.</translation>
</message>
<message>
<source>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</source>
<translation>Taper &lt;b&gt;help&lt;/b&gt; pour afficher une vue générale des commandes proposées.</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>AVERTISSEMENT : des fraudeurs sont réputés être à l'oeuvre, demandant aux utilisateurs de taper des commandes ici, et dérobant le contenu de leurs porte-monnaie. Ne pas utiliser cette console sans une compréhension parfaite des conséquences d'une commande.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>L'activité réseau est désactivée.</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 o</translation>
</message>
@@ -1298,7 +1797,7 @@
</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>
- <translation>Réutilise une adresse de réception précédemment utilisée. Réutiliser une adresse pose des problèmes de sécurité et de vie privée. N'utilisez pas cette option sauf si vous générez à nouveau une demande de paiement déjà faite.</translation>
+ <translation>Réutiliser une adresse de réception utilisée précédemment. Réutiliser une adresse comporte des problèmes de sécurité et de confidentialité. À ne pas utiliser, sauf pour générer une demande de paiement faite au préalable.</translation>
</message>
<message>
<source>R&amp;euse an existing receiving address (not recommended)</source>
@@ -1306,19 +1805,19 @@
</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>Un message optionnel à joindre à la demande de paiement qui sera affiché à l'ouverture de celle-ci. Note : le message ne sera pas envoyé avec le paiement par le réseau Bitcoin.</translation>
+ <translation>Un message facultatif à joindre à la demande de paiement et qui sera affiché à l'ouverture de celle-ci. Note : le message ne sera pas envoyé avec le paiement par le réseau Bitcoin.</translation>
</message>
<message>
<source>An optional label to associate with the new receiving address.</source>
- <translation>Un étiquette optionnelle à associer à la nouvelle adresse de réception</translation>
+ <translation>Un étiquette facultative à associer à la nouvelle adresse de réception.</translation>
</message>
<message>
<source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
- <translation>Utiliser ce formulaire pour demander des paiements. Tous les champs sont &lt;b&gt;optionnels&lt;/b&gt;.</translation>
+ <translation>Utiliser ce formulaire pour demander des paiements. Tous les champs sont &lt;b&gt;facultatifs&lt;/b&gt;.</translation>
</message>
<message>
<source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
- <translation>Un montant optionnel à demander. Laisser ceci vide ou à zéro pour ne pas demander de montant spécifique.</translation>
+ <translation>Un montant facultatif à demander. Ne rien saisir ou un zéro pour ne pas demander de montant spécifique.</translation>
</message>
<message>
<source>Clear all fields of the form.</source>
@@ -1334,11 +1833,11 @@
</message>
<message>
<source>&amp;Request payment</source>
- <translation>&amp;Demande de paiement</translation>
+ <translation>&amp;Demander un paiement</translation>
</message>
<message>
<source>Show the selected request (does the same as double clicking an entry)</source>
- <translation>Afficher la demande choisie (identique à un double-clic sur une entrée)</translation>
+ <translation>Afficher la demande choisie (comme double-cliquer sur une entrée)</translation>
</message>
<message>
<source>Show</source>
@@ -1346,11 +1845,27 @@
</message>
<message>
<source>Remove the selected entries from the list</source>
- <translation>Enlever les entrées sélectionnées de la liste</translation>
+ <translation>Retirer les entrées sélectionnées de la liste</translation>
</message>
<message>
<source>Remove</source>
- <translation>Enlever</translation>
+ <translation>Retirer</translation>
+ </message>
+ <message>
+ <source>Copy URI</source>
+ <translation>Copier l'URI</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copier l’étiquette</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Copier le message</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copier le montant</translation>
</message>
</context>
<context>
@@ -1369,7 +1884,74 @@
</message>
<message>
<source>&amp;Save Image...</source>
- <translation>&amp;Sauvegarder l'image...</translation>
+ <translation>&amp;Enregistrer l'image...</translation>
+ </message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Demande de paiement à %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informations de paiement</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>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>L'URI résultante est trop longue. Essayez de réduire le texte de l'étiquette ou du message.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Erreur d'encodage de l'URI en code QR.</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>
+ <message>
+ <source>(no message)</source>
+ <translation>(aucun message)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(aucun montant demandé)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Demandée</translation>
</message>
</context>
<context>
@@ -1407,10 +1989,6 @@
<translation>Montant :</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorité :</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Frais :</translation>
</message>
@@ -1424,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 ceci est actif mais 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>
@@ -1460,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>Il est correct de payer les frais minimum tant que le volume transactionnel est inférieur à l'espace dans les blocs. Mais soyez conscient que ceci pourrait résulter en une transaction n'étant jamais confirmée une fois qu'il y aura plus de transactions que le réseau ne pourra en traiter.</translation>
+ <translation>Il est correct de payer les frais minimum tant que le volume transactionnel est inférieur à l'espace dans les blocs. Mais soyez conscient que cela pourrait résulter en une transaction n'étant jamais confirmée une fois qu'il y aura plus de transactions que le réseau ne pourra en traiter.</translation>
</message>
<message>
<source>(read the tooltip)</source>
@@ -1476,11 +2054,7 @@
</message>
<message>
<source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
- <translation>(Les frais intelligents ne sont pas encore initialisés. Ceci prend habituellement quelques blocs...)</translation>
- </message>
- <message>
- <source>Confirmation time:</source>
- <translation>Temps de confirmation :</translation>
+ <translation>(Les frais intelligents ne sont pas encore initialisés. Cela prend habituellement quelques blocs...)</translation>
</message>
<message>
<source>normal</source>
@@ -1507,8 +2081,12 @@
<translation>Poussière :</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Estimation du délai de confirmation :</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
- <translation>&amp;Tout nettoyer</translation>
+ <translation>&amp;Tout effacer</translation>
</message>
<message>
<source>Balance:</source>
@@ -1522,6 +2100,126 @@
<source>S&amp;end</source>
<translation>E&amp;nvoyer</translation>
</message>
+ <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>Copy dust</source>
+ <translation>Copier la poussière</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copier la monnaie</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 à %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Voulez-vous vraiment envoyer ?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>ajoutés comme frais de transaction</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Montant total %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>ou</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Confirmer l’envoi de pièces</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>L'adresse du destinataire est invalide. Veuillez la revérifier.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Le montant à payer doit être supérieur à 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Le montant dépasse votre solde.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>Le montant dépasse votre solde lorsque les frais de transaction de %1 sont inclus.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Adresse identique trouvée : chaque adresse ne devrait être utilisée qu'une fois.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Échec de création de la transaction !</translation>
+ </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>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Des frais supérieurs à %1 sont considérés comme ridiculement élevés.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>La demande de paiement a expiré</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n bloc</numerusform><numerusform>%n blocs</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Payer seulement les frais exigés de %1</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Il est estimé que la confirmation commencera dans %n bloc.</numerusform><numerusform>Il est estimé que la confirmation commencera dans %n blocs.</numerusform></translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Avertissement : adresse Bitcoin invalide</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <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>
+ <translation>(aucune étiquette)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1555,7 +2253,7 @@
</message>
<message>
<source>Paste address from clipboard</source>
- <translation>Coller l'adresse depuis le presse-papiers</translation>
+ <translation>Coller l'adresse du presse-papiers</translation>
</message>
<message>
<source>Alt+P</source>
@@ -1563,7 +2261,7 @@
</message>
<message>
<source>Remove this entry</source>
- <translation>Enlever cette entrée</translation>
+ <translation>Retirer cette entrée</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>
@@ -1591,7 +2289,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>Un message qui était joint à l'URI Bitcoin et qui sera stocké avec la transaction pour référence. Note : ce message ne sera pas envoyé par le réseau Bitcoin.</translation>
+ <translation>Un message qui était joint à l'URI bitcoin: et qui sera stocké avec la transaction pour référence. Note : ce message ne sera pas envoyé par le réseau Bitcoin.</translation>
</message>
<message>
<source>Pay To:</source>
@@ -1601,6 +2299,17 @@
<source>Memo:</source>
<translation>Mémo :</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Saisir une étiquette pour cette adresse afin de l’ajouter à votre carnet d’adresses</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Oui</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1610,14 +2319,14 @@
</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>
<name>SignVerifyMessageDialog</name>
<message>
<source>Signatures - Sign / Verify a Message</source>
- <translation>Signatures - Signer / Vérifier un message</translation>
+ <translation>Signatures - Signer / vérifier un message</translation>
</message>
<message>
<source>&amp;Sign Message</source>
@@ -1625,7 +2334,7 @@
</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>Vous pouvez signer des messages/accords avec vos adresses pour prouver que vous pouvez recevoir des bitcoins à ces dernières. Faites attention de ne rien signer de vague ou au hasard, car des attaques d'hameçonnage pourraient essayer de vous faire signer avec votre identité afin de l'usurper. Ne signez que des déclarations entièrement détaillées et avec lesquelles vous êtes d'accord.</translation>
+ <translation>Vous pouvez signer des messages ou des accords avec vos adresses pour prouver que vous pouvez recevoir des bitcoins à ces dernières. Faites attention de ne rien signer de vague ou au hasard, car des attaques d'hameçonnage pourraient essayer de vous faire signer avec votre identité afin de l'usurper. Ne signez que des déclarations entièrement détaillées et avec lesquelles vous êtes d'accord.</translation>
</message>
<message>
<source>The Bitcoin address to sign the message with</source>
@@ -1633,7 +2342,7 @@
</message>
<message>
<source>Choose previously used address</source>
- <translation>Choisir une adresse précédemment utilisée</translation>
+ <translation>Choisir une adresse déjà utilisée</translation>
</message>
<message>
<source>Alt+A</source>
@@ -1641,7 +2350,7 @@
</message>
<message>
<source>Paste address from clipboard</source>
- <translation>Coller une adresse depuis le presse-papiers</translation>
+ <translation>Coller une adresse du presse-papiers</translation>
</message>
<message>
<source>Alt+P</source>
@@ -1661,7 +2370,7 @@
</message>
<message>
<source>Sign the message to prove you own this Bitcoin address</source>
- <translation>Signer le message pour prouver que vous détenez cette adresse Bitcoin</translation>
+ <translation>Signer le message afin de prouver que vous détenez cette adresse Bitcoin</translation>
</message>
<message>
<source>Sign &amp;Message</source>
@@ -1673,7 +2382,7 @@
</message>
<message>
<source>Clear &amp;All</source>
- <translation>&amp;Tout nettoyer</translation>
+ <translation>&amp;Tout effacer</translation>
</message>
<message>
<source>&amp;Verify Message</source>
@@ -1681,7 +2390,7 @@
</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>Saisissez ci-dessous l'adresse de destinataire, le message (assurez-vous de copier exactement les retours à la ligne, les espaces, les tabulations, etc.) et la signature pour vérifier le message. Faites attention à ne pas déduire davantage de la signature que ce qui est contenu dans le message signé même, pour éviter d'être trompé par une attaque d'homme du milieu. Notez que ceci ne fait que prouver que le signataire reçoit l'adresse et ne peut pas prouver la provenance d'une transaction.</translation>
+ <translation>Saisir ci-dessous l'adresse du destinataire, le message (s'assurer de copier fidèlement les retours à la ligne, les espaces, les tabulations, etc.) et la signature pour vérifier le message. Faire attention à ne pas déduire davantage de la signature que ce qui est contenu dans le message signé même, pour éviter d'être trompé par une attaque d'homme du milieu. Prendre en compte que cela ne fait que prouver que le signataire reçoit l'adresse et ne peut pas prouver la provenance d'une transaction !</translation>
</message>
<message>
<source>The Bitcoin address the message was signed with</source>
@@ -1689,7 +2398,7 @@
</message>
<message>
<source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
- <translation>Vérifier le message pour vous assurer qu'il a bien été signé par l'adresse Bitcoin spécifiée</translation>
+ <translation>Vérifier le message pour s'assurer qu'il a été signé avec l'adresse Bitcoin spécifiée</translation>
</message>
<message>
<source>Verify &amp;Message</source>
@@ -1699,6 +2408,58 @@
<source>Reset all verify message fields</source>
<translation>Réinitialiser tous les champs de vérification de message</translation>
</message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Cliquez sur « Signer le message » pour générer la signature</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>L'adresse saisie est invalide.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Veuillez vérifier l'adresse et ressayer.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>L'adresse saisie ne fait pas référence à une clé.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Le déverrouillage du porte-monnaie a été annulé.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>La clé privée n'est pas disponible pour l'adresse saisie.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Échec de signature du message.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Le message a été signé.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>La signature n'a pu être décodée.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Veuillez vérifier la signature et ressayer.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>La signature ne correspond pas au condensé du message.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Échec de vérification du message.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Le message a été vérifié.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1715,11 +2476,460 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Ouvert pendant encore %n bloc</numerusform><numerusform>Ouvert pendant encore %n blocs</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Ouvert jusqu'à %1</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>est en conflit avec une transaction ayant %1 confirmations</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/hors ligne</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/non confirmées, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>dans la réserve de mémoire</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>pas dans la réserve de mémoire</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>abandonnée</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/non confirmée</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 confirmations</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>État</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, n’a pas encore été diffusée avec succès</translation>
+ </message>
+ <message numerus="yes">
+ <source>, broadcast through %n node(s)</source>
+ <translation><numerusform>, diffusée par %n nœud</numerusform><numerusform>, diffusée par %n nœuds</numerusform></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ée</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>De</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>inconnue</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>juste-regarder</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>étiquette</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Crédit</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>arrivera à maturité dans %n bloc</numerusform><numerusform>arrivera à maturité dans %n blocs</numerusform></translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>refusée</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>Transaction fee</source>
+ <translation>Frais de transaction</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>Transaction ID</source>
+ <translation>ID de la transaction</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation>Taille totale de la transaction</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Index de sorties</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Marchand</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>Les pièces générées doivent mûrir pendant %1 blocs avant de pouvoir être dépensées. Lorsque ce bloc a été généré, il a été diffusé sur le réseau pour être ajouté à la chaîne de blocs. Si son intégration à la chaîne échoue, son état sera modifié en « refusée » et il ne sera pas possible de le dépenser. Cela peut arriver occasionnellement si un autre nœud génère un bloc à quelques secondes du vôtre.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Informations de débogage</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transaction</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Entrées</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>
<source>This pane shows a detailed description of the transaction</source>
<translation>Ce panneau affiche une description détaillée de la transaction</translation>
</message>
+ <message>
+ <source>Details for %1</source>
+ <translation>Détails de %1</translation>
+ </message>
+</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 numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Ouvert pendant encore %n bloc</numerusform><numerusform>Ouvert pendant encore %n blocs</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Ouvert jusqu'à %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Hors ligne</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Non confirmée</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Abandonnée</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Confirmation (%1 sur %2 confirmations recommandées)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Confirmée (%1 confirmations)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>En conflit</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Immature (%1 confirmations, sera disponible après %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Ce bloc n’a été reçu par aucun autre nœud et ne sera probablement pas accepté !</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Générée mais refusée</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Reçue avec</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Reçue de</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Envoyée à</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Paiement à vous-même</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Miné</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>juste-regarder</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n.d)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(aucune étiquette)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>État de la transaction. Survoler ce champ avec la souris pour afficher le nombre de confirmations.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Date et heure de réception de la transaction.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Type de transaction.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Une adresse juste-regarder est-elle ou non impliquée dans cette transaction.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Intention/but de la transaction défini par l'utilisateur.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Le montant a été ajouté ou soustrait du solde.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <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>Le mois dernier</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Cette année</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Plage…</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Reçue avec</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Envoyée à</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>À vous-même</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Miné </translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Autres </translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Saisir une adresse ou une étiquette à rechercher</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Montant min.</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Abandonner la transaction</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 la transaction</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Copier la transaction brute</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Copier tous les détails de la transaction</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Modifier l’étiquette </translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Afficher les détails de la transaction</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exporter l'historique transactionnel</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Valeurs séparées par des virgules (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Confirmée</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Juste-regarder</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 d'exportation</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Une erreur est survenue lors de l'enregistrement de l'historique transactionnel vers %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>L'exportation est réussie</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>L'historique transactionnel a été enregistré avec succès vers %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Plage :</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>à </translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1729,6 +2939,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Aucun porte-monnaie n'a été chargé.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Envoyer des pièces</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Exporter</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Exporter les données de l'onglet actuel vers un fichier</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Sauvegarder le porte-monnaie</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Données du porte-monnaie (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Échec de la sauvegarde</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Une erreur est survenue lors de l'enregistrement des données du porte-monnaie vers %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>La sauvegarde est réussie</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Les données du porte-monnaie ont été enregistrées avec succès vers %1</translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1748,7 +3007,19 @@
</message>
<message>
<source>Accept command line and JSON-RPC commands</source>
- <translation>Accepter les commandes de JSON-RPC et de la ligne de commande</translation>
+ <translation>Accepter les commandes JSON-RPC et en ligne de commande</translation>
+ </message>
+ <message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>Accepter des connexions de l'extérieur (par défaut : 1 si aucun -proxy ou -connect/-noconnect)</translation>
+ </message>
+ <message>
+ <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
+ <translation>Se connecter seulement aux nœuds précisés ; -noconnect ou -connect=0 seul pour désactiver les connexions automatiques</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>Distribué sous la licence MIT d'utilisation d'un logiciel. Consulter le fichier joint %s ou %s</translation>
</message>
<message>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
@@ -1763,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>
@@ -1791,16 +3058,12 @@
<translation>Impossible de démarrer le serveur HTTP. Voir le journal de débogage pour plus de détails.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Accepter les connexions entrantes (par défaut : 1 si aucun -proxy ou -connect )</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>La valeur -fallbackfee est très élevée ! Elle représente les frais de transaction que vous pourriez acquitter si aucune estimation de frais n'est proposée.</translation>
+ <source>The %s developers</source>
+ <translation>Les développeurs 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>
@@ -1812,25 +3075,33 @@
</message>
<message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
- <translation>Se lier à l'adresse donnée et toujours l'écouter. Utilisez la notation [host]:port pour l'IPv6</translation>
+ <translation>Se lier à l'adresse donnée et toujours l'écouter. Utiliser la notation [host]:port pour l'IPv6</translation>
</message>
<message>
- <source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
- <translation>Supprimer toutes les transactions du porte-monnaie et ne récupérer que ces parties de la chaîne de blocs avec -rescan au démarrage</translation>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation>Impossible d’obtenir un verrou sur le répertoire de données %s. %s fonctionne probablement déjà.</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribué sous la licence MIT d'utilisation d'un logiciel. Consultez le fichier joint COPYING ou &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
+ <source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
+ <translation>Supprimer toutes les transactions du porte-monnaie et ne récupérer que ces parties de la chaîne de blocs avec -rescan au démarrage</translation>
</message>
<message>
<source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
<translation>Erreur de chargement de %s : vous ne pouvez pas activer HD sur un porte-monnaie non HD existant</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>Erreur de lecture de %s ! Toutes les clés ont été lues correctement, mais les données transactionnelles ou les entrées du carnet d'adresses sont peut-être manquantes ou incorrectes.</translation>
+ </message>
+ <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<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>
@@ -1839,12 +3110,24 @@
<translation>Frais totaux maximaux (en %s) à utiliser en une seule transaction de porte-monnaie ou transaction brute ; les définir trop bas pourrait interrompre les grosses transactions (par défaut : %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>
+ <translation>Veuillez vérifier que l'heure et la date de votre ordinateur sont justes ! Si votre horloge n'est pas à l'heure, %s ne fonctionnera pas correctement.</translation>
+ </message>
+ <message>
<source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
<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 d'exétrons de vérification des scripts (%u à %d, 0 = auto, &lt; 0 = laisser ce nombre de cœurs inutilisés, par défaut : %d)</translation>
+ <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>
<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>
@@ -1852,7 +3135,7 @@
</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>Ceci est une pré-version de test - l'utiliser à vos risques et périls - ne pas l'utiliser pour miner ou pour des applications marchandes</translation>
+ <translation>Ceci est une préversion de test - son utilisation est entièrement à vos risques - ne pas l'utiliser pour miner ou pour des applications marchandes</translation>
</message>
<message>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
@@ -1860,19 +3143,23 @@
</message>
<message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
- <translation>Utiliser l'UPnP pour mapper le port d'écoute (par défaut : 1 lors de l'écoute et pas de mandataire -proxy)</translation>
+ <translation>Utiliser l'UPnP pour mapper le port d'écoute (par défaut : 1 en écoute et sans -proxy)</translation>
</message>
<message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Avertissement : le réseau ne semble pas totalement d'accord ! Quelques mineurs semblent éprouver des difficultés.</translation>
+ <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>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>Avertissement : nous ne semblons pas être en accord complet avec nos pairs ! Vous pourriez avoir besoin d'effectuer une mise à niveau, ou d'autres nœuds du réseau pourraient avoir besoin d'effectuer une mise à niveau.</translation>
+ <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>
<message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Pairs de la liste blanche se connectant à partir du masque réseau ou de l'IP donné. Peut être spécifié plusieurs fois.</translation>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>Avertissement : le réseau ne semble pas totalement d'accord ! Certains mineurs semblent éprouver des problèmes.</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>Avertissement : nous ne semblons pas être en accord complet avec nos pairs ! Une mise à niveau pourrait être nécessaire pour vous ou pour d'autres nœuds du réseau.</translation>
</message>
<message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
@@ -1896,23 +3183,23 @@
</message>
<message>
<source>Attempt to recover private keys from a corrupt wallet on startup</source>
- <translation>Tenter de récupérer les clefs privées d'un porte-monnaie corrompu lors du démarrage</translation>
+ <translation>Tenter de récupérer les clés privées d'un porte-monnaie corrompu lors du démarrage</translation>
</message>
<message>
<source>Block creation options:</source>
- <translation>Options de création de bloc :</translation>
+ <translation>Options de création de blocs :</translation>
</message>
<message>
<source>Cannot resolve -%s address: '%s'</source>
<translation>Impossible de résoudre l'adresse -%s : « %s »</translation>
</message>
<message>
- <source>Change index out of range</source>
- <translation>L'index de changement est hors échelle</translation>
+ <source>Chain selection options:</source>
+ <translation>Options de sélection de la chaîne :</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Ne se connecter qu'au(x) nœud(s) spécifié(s)</translation>
+ <source>Change index out of range</source>
+ <translation>L'index de changement est hors échelle</translation>
</message>
<message>
<source>Connection options:</source>
@@ -1924,7 +3211,7 @@
</message>
<message>
<source>Corrupted block database detected</source>
- <translation>Base corrompue de données des blocs détectée</translation>
+ <translation>Une base de données de blocs corrompue a été détectée</translation>
</message>
<message>
<source>Debugging/Testing options:</source>
@@ -1936,7 +3223,7 @@
</message>
<message>
<source>Do you want to rebuild the block database now?</source>
- <translation>Voulez-vous reconstruire la base de données des blocs maintenant ?</translation>
+ <translation>Voulez-vous reconstruire la base de données de blocs maintenant ?</translation>
</message>
<message>
<source>Enable publish hash block in &lt;address&gt;</source>
@@ -1955,24 +3242,28 @@
<translation>Activer la publication de la transaction brute dans &lt;address&gt;</translation>
</message>
<message>
+ <source>Enable transaction replacement in the memory pool (default: %u)</source>
+ <translation>Activer le remplacement de transactions dans la réserve de mémoire (par défaut : %u)</translation>
+ </message>
+ <message>
<source>Error initializing block database</source>
- <translation>Erreur lors de l'initialisation de la base de données des blocs</translation>
+ <translation>Erreur d'initialisation de la base de données de blocs</translation>
</message>
<message>
<source>Error initializing wallet database environment %s!</source>
- <translation>Erreur lors de l'initialisation de l'environnement de la base de données du porte-monnaie %s !</translation>
+ <translation>Erreur d'initialisation de l'environnement de la base de données du porte-monnaie %s !</translation>
</message>
<message>
<source>Error loading %s</source>
- <translation>Erreur lors du chargement de %s</translation>
+ <translation>Erreur de chargement de %s</translation>
</message>
<message>
<source>Error loading %s: Wallet corrupted</source>
- <translation>Erreur lors du chargement de %s : porte-monnaie corrompu</translation>
+ <translation>Erreur de chargement de %s : porte-monnaie corrompu</translation>
</message>
<message>
<source>Error loading %s: Wallet requires newer version of %s</source>
- <translation>Erreur lors du chargement de %s : le porte-monnaie exige une version plus récente de %s</translation>
+ <translation>Erreur de chargement de %s : le porte-monnaie exige une version plus récente de %s</translation>
</message>
<message>
<source>Error loading %s: You can't disable HD on a already existing HD wallet</source>
@@ -1980,11 +3271,11 @@
</message>
<message>
<source>Error loading block database</source>
- <translation>Erreur du chargement de la base de données des blocs</translation>
+ <translation>Erreur de chargement de la base de données de blocs</translation>
</message>
<message>
<source>Error opening block database</source>
- <translation>Erreur lors de l'ouverture de la base de données des blocs</translation>
+ <translation>Erreur d'ouverture de la base de données de blocs</translation>
</message>
<message>
<source>Error: Disk space is low!</source>
@@ -1992,7 +3283,7 @@
</message>
<message>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
- <translation>Échec de l'écoute sur un port quelconque. Utilisez -listen=0 si vous voulez ceci.</translation>
+ <translation>Échec d'écoute sur un port quelconque. Utiliser -listen=0 si vous le voulez.</translation>
</message>
<message>
<source>Importing...</source>
@@ -2000,7 +3291,11 @@
</message>
<message>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
- <translation>Bloc de genèse incorrect ou introuvable. Mauvais répertoire de données pour le réseau ?</translation>
+ <translation>Bloc de genèse incorrect ou introuvable. Mauvais datadir pour le réseau ?</translation>
+ </message>
+ <message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation>L'initialisation du test de cohérence a échoué. %s est en cours de fermeture. </translation>
</message>
<message>
<source>Invalid -onion address: '%s'</source>
@@ -2027,10 +3322,6 @@
<translation>Emplacement du fichier témoin auth (par défaut : data dir)</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>Octets minimaux par sigop dans les transactions que nous relayons et minons (par défaut : %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>Pas assez de descripteurs de fichiers proposés.</translation>
</message>
@@ -2068,11 +3359,7 @@
</message>
<message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
- <translation>Définir la taille du cache de la base de données en mégaoctets (%d to %d, default: %d)</translation>
- </message>
- <message>
- <source>Set maximum block cost (default: %d)</source>
- <translation>Définir le coût maximal de bloc (par défaut : %d)</translation>
+ <translation>Définir la taille du cache de la base de données en mégaoctets (%d à %d, default: %d)</translation>
</message>
<message>
<source>Set maximum block size in bytes (default: %d)</source>
@@ -2087,6 +3374,10 @@
<translation>Le code source est disponible sur %s.</translation>
</message>
<message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation>Impossible de se lier à %s sur cet ordinateur. %s fonctionne probablement déjà.</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Argument non pris en charge -benchmark ignoré, utiliser -debug=bench.</translation>
</message>
@@ -2103,16 +3394,20 @@
<translation>Utiliser l'UPnP pour mapper le port d'écoute (par défaut : %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Utiliser la chaîne de test</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>Le commentaire d'agent utilisateur (%s) contient des caractères dangereux.</translation>
</message>
<message>
<source>Verifying blocks...</source>
- <translation>Vérification des blocs en cours...</translation>
+ <translation>Vérification des blocs... </translation>
</message>
<message>
<source>Verifying wallet...</source>
- <translation>Vérification du porte-monnaie en cours...</translation>
+ <translation>Vérification du porte-monnaie...</translation>
</message>
<message>
<source>Wallet %s resides outside data directory %s</source>
@@ -2123,6 +3418,10 @@
<translation>Options de débogage/de test du porte-monnaie :</translation>
</message>
<message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>Le porte-monnaie devait être réécrit : redémarrer %s pour terminer l'opération.</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Options du porte-monnaie :</translation>
</message>
@@ -2152,7 +3451,7 @@
</message>
<message>
<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>Exécuter une commande lorsqu'une alerte pertinente est reçue ou si nous voyons une bifurcation vraiment étendue (%s dans la commande est remplacé par le message)</translation>
+ <translation>Exécuter une commande lorsqu'une alerte pertinente est reçue, ou si nous voyons une bifurcation vraiment étendue (%s dans la commande est remplacé par le message)</translation>
</message>
<message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source>
@@ -2171,28 +3470,20 @@
<translation>Quantité maximale de données dans les transactions du porteur de données que nous relayons et minons (par défaut : %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Demander les adresses des pairs par recherche DNS si l'on manque d'adresses (par défaut : 1 sauf si -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
- <translation>Aléer les authentifiants pour chaque connexion mandataire. Ceci active l'isolement de flux de Tor (par défaut : %u) </translation>
+ <translation>Aléer les authentifiants pour chaque connexion mandataire. Cela active l'isolement de flux de Tor (par défaut : %u) </translation>
</message>
<message>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
- <translation>Définir la taille maximale en octets des transactions prioritaires/à frais modiques (par défaut : %d)</translation>
+ <translation>Définir la taille maximale en octets des transactions à priorité élevée et frais modiques (par défaut : %d)</translation>
</message>
<message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation>Le montant de la transaction est trop bas pour être envoyé une fois que les frais ont été déduits</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Ce produit comprend des logiciels développés par le projet OpenSSL pour être utilisés dans la boîte à outils OpenSSL &lt;https://www.openssl.org/&gt; et un logiciel cryptographique écrit par Eric Young, ainsi qu'un logiciel UPnP écrit par Thomas Bernard.</translation>
- </message>
- <message>
<source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
- <translation>Utiliser une génération de clef hiérarchique déterministe (HD) après BIP32. N'a d'effet que lors de la création/premier lancement du porte-monnaie</translation>
+ <translation>Utiliser une génération de clé hiérarchique déterministe (HD) après BIP32. N'a d'effet que lors de la création ou du lancement intitial du porte-monnaie</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>
@@ -2200,7 +3491,7 @@
</message>
<message>
<source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
- <translation>Vous devez reconstruire la base de données en utilisant -reindex afin de revenir au mode sans élagage. Ceci retéléchargera complètement la chaîne de blocs.</translation>
+ <translation>Vous devez reconstruire la base de données en utilisant -reindex afin de revenir au mode sans élagage. Cela retéléchargera complètement la chaîne de blocs.</translation>
</message>
<message>
<source>(default: %u)</source>
@@ -2224,7 +3515,7 @@
</message>
<message>
<source>Imports blocks from external blk000??.dat file on startup</source>
- <translation>Importe des blocs depuis un fichier blk000??.dat externe lors du démarrage</translation>
+ <translation>Importe des blocs à partir d'un fichier blk000??.dat externe lors du démarrage</translation>
</message>
<message>
<source>Information</source>
@@ -2264,7 +3555,7 @@
</message>
<message>
<source>Send trace/debug info to console instead of debug.log file</source>
- <translation>Envoyer les informations de débogage/trace à la console au lieu du fichier debug.log</translation>
+ <translation>Envoyer les infos de débogage/trace à la console au lieu du fichier debug.log</translation>
</message>
<message>
<source>Send transactions as zero-fee transactions if possible (default: %u)</source>
@@ -2276,11 +3567,11 @@
</message>
<message>
<source>Shrink debug.log file on client startup (default: 1 when no -debug)</source>
- <translation>Réduire le fichier debug.log lors du démarrage du client (par défaut : 1 lorsque -debug n'est pas présent)</translation>
+ <translation>Réduire le fichier debug.log lors du démarrage du client (par défaut : 1 sans -debug)</translation>
</message>
<message>
<source>Signing transaction failed</source>
- <translation>La signature de la transaction a échoué</translation>
+ <translation>Échec de signature de la transaction</translation>
</message>
<message>
<source>The transaction amount is too small to pay the fee</source>
@@ -2300,11 +3591,7 @@
</message>
<message>
<source>Transaction amount too small</source>
- <translation>Montant de la transaction trop bas</translation>
- </message>
- <message>
- <source>Transaction amounts must be positive</source>
- <translation>Les montants de transaction doivent être positifs</translation>
+ <translation>Le montant de la transaction est trop bas</translation>
</message>
<message>
<source>Transaction too large for fee policy</source>
@@ -2312,7 +3599,7 @@
</message>
<message>
<source>Transaction too large</source>
- <translation>Transaction trop volumineuse</translation>
+ <translation>La transaction est trop grosse</translation>
</message>
<message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
@@ -2364,25 +3651,29 @@
</message>
<message>
<source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
- <translation>(1 = conserver les métadonnées de transmission, par ex. les informations du propriétaire du compte et de la demande de paiement, 2 = abandonner les métadonnées de transmission)</translation>
+ <translation>(1 = conserver les métadonnées de transmission, p. ex. les informations du propriétaire du compte et de demande de paiement, 2 = abandonner les métadonnées de transmission)</translation>
</message>
<message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
- <translation>-maxtxfee est défini très haut ! Des frais aussi élevés pourraient être payés en une seule transaction.</translation>
- </message>
- <message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee est réglé sur un montant très élevé ! Il s'agit des frais de transaction que vous payerez si vous envoyez une transaction.</translation>
+ <translation>La valeur -maxtxfee est très élevée ! Des frais aussi élevés pourraient être payés en une seule transaction.</translation>
</message>
<message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Ne pas conserver de transactions dans la réserve de mémoire plus de &lt;n&gt; heures (par défaut : %u)</translation>
</message>
<message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Octets équivalents par sigop dans les transactions pour relayer et miner (par défaut : %u)</translation>
+ </message>
+ <message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation>Les frais (en %s/Ko) inférieurs à ce seuil sont considérés comme étant nuls pour la création de transactions (par défaut : %s)</translation>
</message>
<message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>Forcer le relais de transactions des pairs de la liste blanche même s'ils transgressent la politique locale de relais (par défaut : %d)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>Degré de profondeur de la vérification des blocs -checkblocks (0-4, par défaut : %u)</translation>
</message>
@@ -2396,13 +3687,29 @@
</message>
<message>
<source>Output debugging information (default: %u, supplying &lt;category&gt; is optional)</source>
- <translation>Extraire les informations de débogage (par défaut : %u, fournir &lt;category&gt; est optionnel)</translation>
+ <translation>Extraire les informations de débogage (par défaut : %u, fournir &lt;category&gt; est facultatif)</translation>
+ </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>
+ </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>Définit la sérialisation de la transaction brute ou les données hexa de bloc retournées en mode non-verbose, non-segwit(0) ou segwit(1) (par défaut : %d)</translation>
</message>
<message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation>Prendre en charge le filtrage des blocs et des transactions avec les filtres bloom (par défaut : %u)</translation>
</message>
<message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Il s'agit des frais de transaction que vous pourriez payer si aucune estimation de frais n'est proposée.</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>Ce produit comprend des logiciels développés par le Projet OpenSSL pour être utilisés dans la boîte à outils OpenSSL %s, et un logiciel cryptographique écrit par Eric Young, ainsi qu'un logiciel UPnP écrit par 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 taille totale de la chaîne de version de réseau (%i) dépasse la longueur maximale (%i). Réduire le nombre ou la taille des commentaires uacomments.</translation>
</message>
@@ -2423,10 +3730,6 @@
<translation>Utiliser un serveur mandataire SOCKS5 séparé pour atteindre les pairs par les services cachés de Tor (par défaut : %s)</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. 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; vient au format : &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Un script python canonique est inclus dans share/rpcuser. Cette option peut être spécifiée plusieurs fois.</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>Avertissement : des versions de blocs inconnues sont minées ! Il est possible que des règles inconnues soient en vigeur</translation>
</message>
@@ -2435,6 +3738,14 @@
<translation>Avertissement : le fichier du porte-monnaie est corrompu, les données ont été récupérées ! Le fichier %s original a été enregistré en tant que %s dans %s ; si votre solde ou vos transactions sont incorrects, vous devriez restaurer une sauvegarde.</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>Pairs de la liste blanche se connectant à partir de l'adresse IP donnée (p. ex. 1.2.3.4) ou du réseau noté CIDR (p. ex. 1.2.3.0/24). Peut être spécifié plusieurs fois.</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation>La valeur %s est très élevée !</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(par défaut : %s)</translation>
</message>
@@ -2455,6 +3766,10 @@
<translation>Adresse -proxy invalide : « %s »</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>La réserve de clés est épuisée, veuillez d'abord appeler « keypoolrefill »</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>Écouter les connexions JSON-RPC sur &lt;port&gt; (par défaut : %u ou tesnet : %u)</translation>
</message>
@@ -2491,16 +3806,20 @@
<translation>Relayer les multisignatures non-P2SH (par défaut : %u)</translation>
</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>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
- <translation>Définir la taille de la réserve de clefs à &lt;n&gt; (par défaut : %u)</translation>
+ <translation>Définir la taille de la réserve de clés à &lt;n&gt; (par défaut : %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Définir la taille de bloc minimale en octets (par défaut : %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Définir le poids maximal de bloc BIP141 (par défaut : %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
- <translation>Définir le nombre d'exétrons pour desservir les appels RPC (par défaut : %d)</translation>
+ <translation>Définir le nombre de fils pour les appels RPC (par défaut : %d)</translation>
</message>
<message>
<source>Specify configuration file (default: %s)</source>
@@ -2519,12 +3838,40 @@
<translation>Dépenser la monnaie non confirmée lors de l'envoi de transactions (par défaut : %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Démarrage des processus réseau...</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>Le porte-monnaie évitera de payer moins que les frais minimaux de relais. </translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Il s'agit des frais minimaux que vous payez pour chaque transaction. </translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Il s'agit des frais minimaux que vous payez si vous envoyez une transaction.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Seuil de déconnexion des pairs présentant un mauvais comportement (par défaut : %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Les montants transactionnels ne doivent pas être négatifs</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>La chaîne de la réserve de mémoire de la transaction est trop longue</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>La transaction doit comporter au moins un destinataire</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
- <translation>Réseau inconnu spécifié sur -onlynet : « %s »</translation>
+ <translation>Réseau inconnu spécifié dans -onlynet : « %s »</translation>
</message>
<message>
<source>Insufficient funds</source>
diff --git a/src/qt/locale/bitcoin_fr_CA.ts b/src/qt/locale/bitcoin_fr_CA.ts
index fca1e62883..02701cbf1d 100644
--- a/src/qt/locale/bitcoin_fr_CA.ts
+++ b/src/qt/locale/bitcoin_fr_CA.ts
@@ -13,7 +13,10 @@
<source>&amp;Delete</source>
<translation>&amp;Supprimer</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -28,7 +31,7 @@
<source>Repeat new passphrase</source>
<translation>Répéter Mot de Passe</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -52,7 +55,7 @@
<source>&amp;Address</source>
<translation>Addresse</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -67,6 +70,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -76,12 +82,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -91,12 +106,18 @@
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -109,12 +130,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_fr_FR.ts b/src/qt/locale/bitcoin_fr_FR.ts
index a6f6ac4fd1..4d02aa5114 100644
--- a/src/qt/locale/bitcoin_fr_FR.ts
+++ b/src/qt/locale/bitcoin_fr_FR.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Supprimer</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Répétez la phrase de passe</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -259,30 +262,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 numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n heure</numerusform><numerusform>%n heures</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n jour</numerusform><numerusform>%n jours</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n semaine</numerusform><numerusform>%n semaines</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 et %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n an</numerusform><numerusform>%n années</numerusform></translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>en retard de %1</translation>
</message>
@@ -364,7 +343,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Le porte-monnaie est &lt;b&gt;chiffré&lt;/b&gt; et est actuellement &lt;b&gt;verrouillé&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -384,10 +363,6 @@
<translation>Montant :</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorité:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Frais:</translation>
</message>
@@ -439,11 +414,7 @@
<source>Confirmed</source>
<translation>Confirmée</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Priorité</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -458,7 +429,7 @@
<source>&amp;Address</source>
<translation>&amp;Adresse</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -549,6 +520,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulaire</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Cacher</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -566,7 +548,7 @@
<source>Select payment request file</source>
<translation>Sélectionner un fichier de demande de paiement</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -754,6 +736,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -763,11 +748,7 @@
<source>Node/Service</source>
<translation>Nœud/Service </translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Temps du ping</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -806,7 +787,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 et %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -1064,7 +1055,7 @@
<source>Remove</source>
<translation>Retirer</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1083,7 +1074,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Sauvegarder image</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1115,10 +1109,6 @@
<translation>Montant :</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorité:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Frais:</translation>
</message>
@@ -1155,10 +1145,6 @@
<translation>Recommandé: </translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Temps de confirmation:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1190,6 +1176,10 @@
<source>Confirm the send action</source>
<translation>Confirmer l'action d'envoi</translation>
</message>
+ <message>
+ <source>S&amp;end</source>
+ <translation>E&amp;voyer</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1241,7 +1231,10 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
</context>
@@ -1311,16 +1304,34 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Ce panneau affiche une description détaillée de la transaction</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1420,10 +1431,6 @@ Importation ...</translation>
<translation>Montant de la transaction trop bas</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Les montants de la transaction doivent être positif</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Montant de la transaction trop élevé pour la politique de frais</translation>
</message>
diff --git a/src/qt/locale/bitcoin_gl.ts b/src/qt/locale/bitcoin_gl.ts
index 9aa7b55096..ff0804d79b 100644
--- a/src/qt/locale/bitcoin_gl.ts
+++ b/src/qt/locale/bitcoin_gl.ts
@@ -37,7 +37,10 @@
<source>&amp;Delete</source>
<translation>&amp;Borrar</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -56,7 +59,7 @@
<source>Repeat new passphrase</source>
<translation>Repite novo contrasinal</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -223,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>
@@ -274,7 +273,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>O moedeiro está &lt;b&gt;encriptado&lt;/b&gt; e actualmente &lt;b&gt;bloqueado&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -290,10 +289,6 @@
<translation>Importe:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridade:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Pago:</translation>
</message>
@@ -329,11 +324,7 @@
<source>Confirmed</source>
<translation>Confirmado</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioridade</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -356,7 +347,7 @@
<source>&amp;Address</source>
<translation>&amp;Dirección</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -419,6 +410,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulario</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Hora do último bloque</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -436,7 +438,7 @@
<source>Select payment request file</source>
<translation>Seleccionar ficheiro de solicitude de pago</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -572,6 +574,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -594,6 +599,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>N/A</source>
@@ -749,7 +760,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Gardar Imaxe...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -773,10 +787,6 @@
<translation>Importe:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridade:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Pago:</translation>
</message>
@@ -816,7 +826,7 @@
<source>S&amp;end</source>
<translation>&amp;Enviar</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -871,7 +881,10 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
</context>
@@ -945,7 +958,7 @@
<source>Reset all verify message fields</source>
<translation>Restaurar todos os campos de verificación de mensaxe</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -961,16 +974,34 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Este panel amosa unha descripción detallada da transacción</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -997,10 +1028,6 @@
<translation>Executar no fondo como un demo e aceptar comandos</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Aceptar conexións de fóra (por defecto: 1 se non -proxy ou -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Core de Bitcoin</translation>
</message>
@@ -1013,18 +1040,6 @@
<translation>Executar comando cando unha transacción do moedeiro cambia (%s no comando é substituído por TxID)</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 é unha build de test pre-lanzamento - emprégaa baixo o teu propio risco - non empregar para minado ou aplicacións de comerciantes</translation>
- </message>
- <message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Precaución: A rede non parece estar totalmente de acordo! Algúns mineitos 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>Precaución: Non parece que esteamos totalmente de acordo cos nosos pares! Pode que precises actualizar, ou outros nodos poden precisar actualizarse.</translation>
- </message>
- <message>
<source>&lt;category&gt; can be:</source>
<translation>&lt;categoría&gt; pode ser:</translation>
</message>
@@ -1033,10 +1048,6 @@
<translation>Opcións de creación de bloque:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Conectar so ao(s) nodo(s) especificado(s)</translation>
- </message>
- <message>
<source>Corrupted block database detected</source>
<translation>Detectada base de datos de bloques corrupta.</translation>
</message>
@@ -1121,10 +1132,6 @@
<translation>A cantidade da transacción é demasiado pequena</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>As cantidades da transacción deben ser positivas</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>A transacción é demasiado grande</translation>
</message>
diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts
index 4a293c1c3f..78ef446ff1 100644
--- a/src/qt/locale/bitcoin_he.ts
+++ b/src/qt/locale/bitcoin_he.ts
@@ -41,6 +41,69 @@
<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>בחר</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>&amp;העתק כתובת</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>העתק &amp;תוית</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;ערוך</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>
+ <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>
@@ -60,7 +123,7 @@
<source>Repeat new passphrase</source>
<translation>נא לחזור על מילת הצופן החדשה</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -255,14 +318,6 @@
<translation>מעבד בלוקים על הדיסק...</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>אין מקור מקטעים זמין…</translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 ו%2</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 מאחור</translation>
</message>
@@ -310,7 +365,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -330,10 +385,6 @@
<translation>סכום:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>עדיפות:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>עמלה:</translation>
</message>
@@ -386,10 +437,10 @@
<translation>מאושר</translation>
</message>
<message>
- <source>Priority</source>
- <translation>עדיפות</translation>
+ <source>(no label)</source>
+ <translation>(ללא תוית)</translation>
</message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -412,7 +463,7 @@
<source>&amp;Address</source>
<translation>&amp;כתובת</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -467,6 +518,10 @@
<translation>התחל ממוזער</translation>
</message>
<message>
+ <source>Show splash screen on startup (default: %u)</source>
+ <translation>הצג מסך פתיחה בעת הפעלה (ברירת מחדל: %u)</translation>
+ </message>
+ <message>
<source>Reset all settings changed in the GUI</source>
<translation>איפוס כל שינויי הגדרות התצוגה</translation>
</message>
@@ -499,6 +554,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>טופס</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>זמן המקטע האחרון</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>הסתר</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -516,7 +586,7 @@
<source>Select payment request file</source>
<translation>בחירת קובץ בקשת תשלום</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -776,16 +846,15 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
<translation>סוכן משתמש</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>זמן המענה</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -824,7 +893,17 @@
<source>%1 ms</source>
<translation>%1 מילישניות</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 ו%2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -1012,8 +1091,8 @@
<translation>ניקוי מסוף הבקרה</translation>
</message>
<message>
- <source>Ban Node for</source>
- <translation>חסום משתמש ל</translation>
+ <source>1 &amp;hour</source>
+ <translation>1 שעה</translation>
</message>
<message>
<source>1 &amp;day</source>
@@ -1150,7 +1229,7 @@
<source>Remove</source>
<translation>הסרה</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1169,7 +1248,26 @@
<source>&amp;Save Image...</source>
<translation>&amp;שמירת תמונה…</translation>
</message>
-</context>
+ <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>
<message>
@@ -1205,10 +1303,6 @@
<translation>סכום:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>עדיפות:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>עמלה:</translation>
</message>
@@ -1257,10 +1351,6 @@
<translation>מותאם אישית:</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>זמן האישור:</translation>
- </message>
- <message>
<source>normal</source>
<translation>רגיל</translation>
</message>
@@ -1300,6 +1390,10 @@
<source>S&amp;end</source>
<translation>&amp;שליחה</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ללא תוית)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1367,7 +1461,10 @@
<source>Memo:</source>
<translation>תזכורת:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1453,7 +1550,7 @@
<source>Reset all verify message fields</source>
<translation>איפוס כל שדות אימות ההודעה</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1469,12 +1566,41 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>חלונית זו מציגה תיאור מפורט של ההעברה</translation>
</message>
-</context>
+ </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>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>
<message>
@@ -1483,6 +1609,15 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1513,10 +1648,6 @@
<translation>ריצה כסוכן ברקע וקבלת פקודות</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>קבלת חיבורים מבחוץ (בררת מחדל: 1 ללא ‎-proxy או ‎-connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>ליבת ביטקוין</translation>
</message>
@@ -1537,18 +1668,6 @@
<translation>ביצוע פקודה כאשר העברה בארנק משתנה (%s ב־cmd יוחלף ב־TxID)</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>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>&lt;category&gt; can be:</source>
<translation>&lt;קטגוריה&gt; יכולה להיות:</translation>
</message>
@@ -1561,10 +1680,6 @@
<translation>אינדקס העודף מחוץ לתחום</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>התחבר רק לצמתים המצוינים</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>הגדרות חיבור:</translation>
</message>
@@ -1737,10 +1852,6 @@
<translation>סכום ההעברה קטן מדי</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>סכומי ההעברות חייבים להיות חיוביים</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>ההעברה גבוהה מדי עבור מדיניות העמלות</translation>
</message>
diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts
index 86c53b4ce3..20fbd0e0ae 100644
--- a/src/qt/locale/bitcoin_hi_IN.ts
+++ b/src/qt/locale/bitcoin_hi_IN.ts
@@ -13,7 +13,10 @@
<source>&amp;Delete</source>
<translation>&amp;मिटाए !!</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -28,7 +31,7 @@
<source>Repeat new passphrase</source>
<translation>दोबारा नया पहचान शब्द/अक्षर डालिए !</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -135,7 +138,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>वॉलेट एन्क्रिप्टेड है तथा अभी लॉक्ड है</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -169,7 +172,7 @@
<source>&amp;Address</source>
<translation>&amp;पता</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -192,6 +195,13 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>फार्म</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -221,6 +231,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -236,6 +249,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>N/A</source>
@@ -266,6 +285,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -320,6 +342,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -352,16 +377,34 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation> ये खिड़की आपको लेन-देन का विस्तृत विवरण देगी !</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts
index f5accfb0b8..3956669ad4 100644
--- a/src/qt/locale/bitcoin_hr.ts
+++ b/src/qt/locale/bitcoin_hr.ts
@@ -41,7 +41,34 @@
<source>&amp;Delete</source>
<translation>Iz&amp;briši</translation>
</message>
-</context>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Odaberi adresu na koju šalješ novac</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Odaberi adresu na koju primaš novac</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Odaberi</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>Ovo su vaše Bitcoin adrese za slanje novca. Uvijek provjerite iznos i adresu primatelja prije slanja novca.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopiraj adresu</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Izvoz neuspješan</translation>
+ </message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +87,7 @@
<source>Repeat new passphrase</source>
<translation>Ponovite novu lozinku</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -250,26 +277,6 @@
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Obrađen %n blok povijesti transakcije.</numerusform><numerusform>Obrađeno %n bloka povijesti transakcije.</numerusform><numerusform>Obrađeno %n blokova povijesti transakcije.</numerusform></translation>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n sat</numerusform><numerusform>%n sata</numerusform><numerusform>%n sati</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n dan</numerusform><numerusform>%n dana</numerusform><numerusform>%n dana</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n tjedan</numerusform><numerusform>%n tjedna</numerusform><numerusform>%n tjedana</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 i %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n godina</numerusform><numerusform>%n godine</numerusform><numerusform>%n godina</numerusform></translation>
- </message>
<message>
<source>Last received block was generated %1 ago.</source>
<translation>Zadnji primljeni blok je bio ustvaren prije %1.</translation>
@@ -344,7 +351,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Novčanik je &lt;b&gt;šifriran&lt;/b&gt; i trenutno &lt;b&gt;zaključan&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -364,10 +371,6 @@
<translation>Iznos:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioriteta:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Naknada:</translation>
</message>
@@ -407,11 +410,7 @@
<source>Confirmed</source>
<translation>Potvrđeno</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioriteta</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -434,7 +433,7 @@
<source>&amp;Address</source>
<translation>&amp;Adresa</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -485,6 +484,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Oblik</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Posljednje vrijeme bloka</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -502,7 +512,7 @@
<source>Select payment request file</source>
<translation>Izaberi datoteku zahtjeva za plaćanje</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -642,6 +652,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -654,6 +667,16 @@
<source>N/A</source>
<translation>N/A</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 i %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -791,7 +814,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Spremi sliku...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -815,10 +841,6 @@
<translation>Iznos:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioriteta:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Naknada:</translation>
</message>
@@ -862,7 +884,7 @@
<source>S&amp;end</source>
<translation>&amp;Pošalji</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -899,6 +921,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -955,16 +980,38 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Ovaj prozor prikazuje detaljni opis transakcije</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Izvoz neuspješan</translation>
+ </message>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -995,10 +1042,6 @@
<translation>Opcije za kreiranje bloka:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Poveži se samo sa određenim čvorom/čvorovima</translation>
- </message>
- <message>
<source>Error: Disk space is low!</source>
<translation>Pogreška: Nema dovoljno prostora na disku!</translation>
</message>
diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts
index 9eb0cf76c4..28270e8c2e 100644
--- a/src/qt/locale/bitcoin_hu.ts
+++ b/src/qt/locale/bitcoin_hu.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Törlés</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,10 +63,18 @@
<source>Repeat new passphrase</source>
<translation>Új jelszó újra</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
- </context>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP-cím/maszk</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Kitiltás vége</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
@@ -246,34 +257,10 @@
<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>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n óra</numerusform><numerusform>%n óra</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n nap</numerusform><numerusform>%n nap</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n hét</numerusform><numerusform>%n hét</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 és %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n év</numerusform><numerusform>%n év</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 lemaradás</translation>
@@ -352,7 +339,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Tárca &lt;b&gt;kódolva&lt;/b&gt; és jelenleg &lt;b&gt;zárva&lt;/b&gt;.</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -372,10 +359,6 @@
<translation>Összeg:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritás:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Díj:</translation>
</message>
@@ -427,11 +410,7 @@
<source>Confirmed</source>
<translation>Megerősítve</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioritás</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -454,7 +433,7 @@
<source>&amp;Address</source>
<translation>&amp;Cím</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -525,6 +504,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Űrlap</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Utolsó blokk ideje</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Elrejtés</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -542,7 +536,7 @@
<source>Select payment request file</source>
<translation>Fizetési kérelmi fájl kiválasztása</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -754,16 +748,15 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
<translation>User Agent</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Ping idő</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -802,7 +795,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 és %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -870,6 +873,10 @@
<translation>&amp;Peerek</translation>
</message>
<message>
+ <source>Banned peers</source>
+ <translation>Kitiltott felek</translation>
+ </message>
+ <message>
<source>Select a peer to view detailed information.</source>
<translation>Peer kijelölése a részletes információkért</translation>
</message>
@@ -1052,7 +1059,7 @@
<source>Remove</source>
<translation>Eltávolítás</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1071,7 +1078,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Kép mentése</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1103,10 +1113,6 @@
<translation>Összeg:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritás:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Díjak:</translation>
</message>
@@ -1182,7 +1188,7 @@
<source>S&amp;end</source>
<translation>&amp;Küldés</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1229,7 +1235,10 @@
<source>Memo:</source>
<translation>Jegyzet:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1311,16 +1320,34 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Ez a mező a tranzakció részleteit mutatja</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1351,10 +1378,6 @@
</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Kívülről érkező kapcsolatok elfogadása (alapértelmezett: 1, ha nem használt a -proxy vagy a -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1363,8 +1386,8 @@
<translation>Parancs, amit akkor hajt végre, amikor egy tárca-tranzakció megváltozik (%s a parancsban lecserélődik a blokk TxID-re)</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Csatlakozás csak a megadott csomóponthoz</translation>
+ <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
+ <translation>UPnP használata porttovábbításra (alapértelmezett: 1, amikor kiszolgál és nem használt a -proxy)</translation>
</message>
<message>
<source>Corrupted block database detected</source>
@@ -1407,6 +1430,10 @@
<translation>Helytelen vagy nemlétező genézis blokk. Helytelen hálózati adatkönyvtár?</translation>
</message>
<message>
+ <source>Loading banlist...</source>
+ <translation>Tiltólista betöltése...</translation>
+ </message>
+ <message>
<source>Not enough file descriptors available.</source>
<translation>Nincs elég fájlleíró. </translation>
</message>
@@ -1423,6 +1450,18 @@
<translation>Tárca beállítások:</translation>
</message>
<message>
+ <source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source>
+ <translation>Saját IP-cím felfedezése (alapértelmezett: 1, amikor kiszolgál és nem használt a -externalip)</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>A fehérlistán szereplő felek nem lesznek automatikusan kitiltva és a tranzakcióik is mindig továbbítva lesznek, akkor is ha már a megerősítésre váró listán (mempool) vannak. Hasznos például összekötő csomópontokon (gateway).</translation>
+ </message>
+ <message>
+ <source>(default: %u)</source>
+ <translation>(alapértelmezett: %u)</translation>
+ </message>
+ <message>
<source>Error reading from database, shutting down.</source>
<translation>Hiba az adatbázis olvasásakor, leállítás</translation>
</message>
@@ -1447,10 +1486,6 @@
<translation>Tranzakció összege túl alacsony</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Tranzakció összege pozitív kell legyen</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>Túl nagy tranzakció</translation>
</message>
@@ -1481,6 +1516,14 @@
<translation>Címek betöltése...</translation>
</message>
<message>
+ <source>(default: %s)</source>
+ <translation>(alapértelmezett: %s)</translation>
+ </message>
+ <message>
+ <source>Include IP addresses in debug output (default: %u)</source>
+ <translation>IP-címek megjelenítése a naplóban (alapértelmezett: %u)</translation>
+ </message>
+ <message>
<source>Invalid -proxy address: '%s'</source>
<translation>Érvénytelen -proxy cím: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_id_ID.ts b/src/qt/locale/bitcoin_id_ID.ts
index feb6f690c4..fd77f07cd8 100644
--- a/src/qt/locale/bitcoin_id_ID.ts
+++ b/src/qt/locale/bitcoin_id_ID.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Hapus</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Ulangi kata kunci baru</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -250,34 +253,10 @@
<source>%n active connection(s) to Bitcoin network</source>
<translation><numerusform>%n koneksi aktif ke jaringan Bitcoin</numerusform></translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Sumber blok tidak tersedia...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>%n blok dari riwayat transaksi diproses.</numerusform></translation>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n jam</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n hari</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n minggu</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 dan %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n tahun</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>kurang %1</translation>
@@ -356,7 +335,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -376,10 +355,6 @@
<translation>Jumlah:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritas:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Biaya:</translation>
</message>
@@ -431,11 +406,7 @@
<source>Confirmed</source>
<translation>Terkonfirmasi</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioritas</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -458,7 +429,7 @@
<source>&amp;Address</source>
<translation>&amp;Alamat</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -561,6 +532,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulir</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Waktu blok terakhir</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -578,7 +560,7 @@
<source>Select payment request file</source>
<translation>Pilih data permintaan pembayaran</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -822,6 +804,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -850,6 +835,16 @@
<source>N/A</source>
<translation>T/S</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 dan %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -1070,7 +1065,7 @@
<source>Remove</source>
<translation>Menghapus</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1089,7 +1084,14 @@
<source>&amp;Save Image...</source>
<translation>&amp;Simpan Gambaran...</translation>
</message>
-</context>
+ <message>
+ <source>Amount</source>
+ <translation>Jumlah</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1125,10 +1127,6 @@
<translation>Nilai:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritas:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Biaya:</translation>
</message>
@@ -1157,10 +1155,6 @@
<translation>Disarankan</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Waktu konfirmasi:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1200,7 +1194,7 @@
<source>S&amp;end</source>
<translation>K&amp;irim</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1255,7 +1249,10 @@
<source>Memo:</source>
<translation>Catatan Peringatan:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1329,7 +1326,7 @@
<source>Reset all verify message fields</source>
<translation>Hapus semua bidang verifikasi pesan</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1345,16 +1342,38 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Amount</source>
+ <translation>Jumlah</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Jendela ini menampilkan deskripsi rinci dari transaksi tersebut</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1381,10 +1400,6 @@
<translation>Berjalan dibelakang sebagai daemin dan menerima perintah</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Terima hubungan dari luar (standar: 1 kalau -proxy atau -connect tidak dipilih)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1393,22 +1408,10 @@
<translation>Jalankan perintah ketika perubahan transaksi dompet (%s di cmd digantikan oleh TxID)</translation>
</message>
<message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Peringatan: Jaringan tidak semua bersetuju! Beberapa penambang dapat persoalan.</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>Peringatan: Kami tidak bersetujuh dengan peer-peer kami! Kemungkinan Anda harus upgrade, atau node-node lain yang harus diupgrade.</translation>
- </message>
- <message>
<source>Block creation options:</source>
<translation>Pilihan pembuatan blok:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Jangan menghubungkan node(-node) selain yang di daftar</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Pilih koneksi:</translation>
</message>
@@ -1513,10 +1516,6 @@
<translation>Nilai transaksi terlalu kecil</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Nilai transaksi harus positif</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>Transaksi terlalu besar</translation>
</message>
diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts
index 55bc9c3c82..9f2c7626de 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'etichetta</translation>
+ <translation>Fare clic con il tasto destro del mouse per modificare l'indirizzo o l'etichettadefault</translation>
</message>
<message>
<source>Create a new address</source>
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Elimina</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Scegli l'indirizzo a cui inviare bitcoin</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Scegli l'indirizzo con cui ricevere bitcoin</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>Sc&amp;egli</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Indirizzi d'invio</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Indirizzi di ricezione</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>Questo è un elenco di indirizzi Bitcoin a cui puoi inviare pagamenti. Controlla sempre l'importo e l'indirizzo del beneficiario prima di inviare 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>Questi sono i tuoi indirizzi Bitcoin che puoi usare per ricevere pagamenti. Si raccomanda di generare un nuovo indirizzo per ogni transazione.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Copia l'indirizzo</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copia &amp;l'etichetta</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Modifica</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Esporta Lista Indirizzi</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Testo CSV (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Esportazione Fallita</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Si è verificato un errore tentando di salvare la lista degli indirizzi su %1. Si prega di riprovare.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etichetta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Indirizzo</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(nessuna etichetta)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,7 +131,67 @@
<source>Repeat new passphrase</source>
<translation>Ripeti la nuova passphrase</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>Inserisci la nuova passphrase per il portamonete.&lt;br/&gt;Si consiglia di utilizzare &lt;b&gt;almeno dieci caratteri casuali&lt;/b&gt; oppure &lt;b&gt;otto o più parole&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Cifra il portamonete</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Questa operazione necessita della passphrase per sbloccare il portamonete.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Sblocca il portamonete</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Quest'operazione necessita della passphrase per decifrare il portamonete,</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Decifra il portamonete</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Cambia la passphrase</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Inserisci la vecchia e la nuova passphrase per il portamonete.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Conferma la cifratura del portamonete</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>Attenzione: perdendo la passphrase di un portamonete cifrato &lt;b&gt;TUTTI I PROPRI BITCOIN ANDRANNO PERSI&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Si è sicuri di voler cifrare il portamonete?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Portamonete cifrato</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Il processo di crittografia del tuo portafogli è fallito</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Sbloccaggio del portafoglio fallito</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>La frase inserita per decrittografare il tuo portafoglio è incorretta</translation>
+ </message>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -115,6 +246,10 @@
<translation>&amp;Informazioni su %1</translation>
</message>
<message>
+ <source>Show information about %1</source>
+ <translation>Mostra informazioni su %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>Informazioni su &amp;Qt</translation>
</message>
@@ -127,6 +262,10 @@
<translation>&amp;Opzioni...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Modifica le opzioni di configurazione per %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Cifra il portamonete...</translation>
</message>
@@ -255,32 +394,16 @@
<translation><numerusform>%n connessione attiva alla rete Bitcoin</numerusform><numerusform>%n connessioni alla rete Bitcoin attive</numerusform></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>
- </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>
+ <source>Indexing blocks on disk...</source>
+ <translation>Indicizzando i blocchi su disco...</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 e %2</translation>
+ <source>Processing blocks on disk...</source>
+ <translation>Processando i blocchi su disco...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n anno</numerusform><numerusform>%n anni</numerusform></translation>
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>Elaborato %n blocco dello storico transazioni.</numerusform><numerusform>Elaborati %n blocchi dello storico transazioni.</numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -311,6 +434,14 @@
<translation>Aggiornato</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Mostra il messaggio di aiuto di %1 per ottenere una lista di opzioni di comando per Bitcoin </translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>%1 client</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>In aggiornamento...</translation>
</message>
@@ -360,7 +491,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -380,10 +511,6 @@
<translation>Importo:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorità:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Commissione:</translation>
</message>
@@ -436,10 +563,10 @@
<translation>Confermato</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Priorità</translation>
+ <source>(no label)</source>
+ <translation>(nessuna etichetta)</translation>
</message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -462,7 +589,7 @@
<source>&amp;Address</source>
<translation>&amp;Indirizzo</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -497,6 +624,10 @@
<translation>(%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>Informazioni %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Opzioni della riga di comando</translation>
</message>
@@ -532,7 +663,11 @@
<source>Show splash screen on startup (default: %u)</source>
<translation>Mostra schermata iniziale all'avvio (default: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Reimposta tutti i campi dell'interfaccia grafica</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -540,6 +675,18 @@
<translation>Benvenuto</translation>
</message>
<message>
+ <source>Welcome to %1.</source>
+ <translation>Benvenuto su %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>Dato che questa è la prima volta che il programma viene lanciato, puoi scegliere dove %1 salverà i suoi dati.</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>%1 scaricherà e salverà una copia della Blockchain di Bitcoin. Saranno salvati almeno %2GB di dati in questo percorso e continueranno ad aumentare col tempo. Anche il portafoglio verrà salvato in questo percorso.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Usa la cartella dati predefinita</translation>
</message>
@@ -556,15 +703,26 @@
<translation>Errore</translation>
</message>
<message numerus="yes">
- <source>%n GB of free space available</source>
- <translation><numerusform>GB di spazio libero disponibile</numerusform><numerusform>%n GB di spazio disponibile</numerusform></translation>
- </message>
- <message numerus="yes">
<source>(of %n GB needed)</source>
<translation><numerusform>(di %nGB richiesti)</numerusform><numerusform>(%n GB richiesti)</numerusform></translation>
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Modulo</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Ora del blocco più recente</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Nascondi</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -582,7 +740,7 @@
<source>Select payment request file</source>
<translation>Seleziona il file di richiesta di pagamento</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -594,6 +752,14 @@
<translation>&amp;Principale</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>Avvia automaticamente %1 una volta effettuato l'accesso al sistema.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>&amp;Start %1 all'accesso al sistema</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>Dimensione della cache del &amp;database.</translation>
</message>
@@ -731,6 +897,14 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>&amp;Finestra</translation>
</message>
<message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>&amp;Nascondi l'icona nella barra delle applicazioni.</translation>
+ </message>
+ <message>
+ <source>Hide tray icon</source>
+ <translation>Nascondi l'icona della barra applicazioni</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation>Mostra solo nella tray bar quando si riduce ad icona.</translation>
</message>
@@ -751,6 +925,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>&amp;Lingua Interfaccia Utente:</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>La lingua dell'interfaccia utente può essere impostata qui. L'impostazione avrà effetto dopo il riavvio %1.</translation>
+ </message>
+ <message>
<source>&amp;Unit to show amounts in:</source>
<translation>&amp;Unità di misura con cui visualizzare gli importi:</translation>
</message>
@@ -875,6 +1053,9 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -884,11 +1065,7 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>Node/Service</source>
<translation>Nodo/Servizio</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Tempo di ping</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -927,7 +1104,17 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 e %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -955,6 +1142,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Versione BerkeleyDB in uso</translation>
</message>
<message>
+ <source>Datadir</source>
+ <translation>Datadir</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>Ora di avvio</translation>
</message>
@@ -1039,6 +1230,18 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>User Agent</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>Apri il file log del debug di %1 dalla cartella dati attuale. Può richiedere alcuni secondi per file di log di grandi dimensioni.</translation>
+ </message>
+ <message>
+ <source>Decrease font size</source>
+ <translation>Riduci dimensioni font.</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation>Aumenta dimensioni font</translation>
+ </message>
+ <message>
<source>Services</source>
<translation>Servizi</translation>
</message>
@@ -1115,14 +1318,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Cancella console</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Nodo Disconnesso</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Nodo Bannato perché</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;ora</translation>
</message>
@@ -1139,8 +1334,8 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>1 &amp;anno</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Elimina Ban Nodo</translation>
+ <source>Welcome to the %1 RPC console.</source>
+ <translation>Benvenuto nella console RPC di %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>
@@ -1269,7 +1464,7 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>Remove</source>
<translation>Rimuovi</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1288,7 +1483,26 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>&amp;Save Image...</source>
<translation>&amp;Salva Immagine...</translation>
</message>
-</context>
+ <message>
+ <source>Address</source>
+ <translation>Indirizzo</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etichetta</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etichetta</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(nessuna etichetta)</translation>
+ </message>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1324,10 +1538,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Importo:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorità:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Commissione:</translation>
</message>
@@ -1396,10 +1606,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>(Commissione intelligente non ancora inizializzata. Normalmente richiede un'attesa di alcuni blocchi...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Tempo di conferma:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normale</translation>
</message>
@@ -1439,6 +1645,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>S&amp;end</source>
<translation>&amp;Invia</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation>(nessuna etichetta)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1518,10 +1728,17 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>Memo:</source>
<translation>Memo:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down...</source>
+ <translation>Arresto di %1 in corso...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation>Non spegnere il computer fino a quando questa finestra non si sarà chiusa.</translation>
</message>
@@ -1612,7 +1829,7 @@ 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>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1628,12 +1845,45 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Questo pannello mostra una descrizione dettagliata della transazione</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etichetta</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(nessuna etichetta)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Testo CSV (*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etichetta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Indirizzo</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Esportazione Fallita</translation>
+ </message>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1642,6 +1892,15 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1676,10 +1935,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>
@@ -1704,30 +1959,62 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Impossibile avviare il server HTTP. Dettagli nel log di debug.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Accetta connessioni dall'esterno (predefinito: 1 se -proxy o -connect non sono utilizzati)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
+ <source>The %s developers</source>
+ <translation>Sviluppatori di %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>Un importo (in %s/kB) che sarà utilizzato quando la stima delle commissioni non ha abbastanza dati (default: %s)</translation>
+ </message>
+ <message>
+ <source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
+ <translation>Accetta le transazioni trasmesse ricevute da peers in whitelist anche se non si stanno trasmettendo transazioni (default: %d)</translation>
+ </message>
+ <message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
<translation>Associa all'indirizzo indicato e resta permanentemente in ascolto su di esso. Usa la notazione [host]:porta per l'IPv6</translation>
</message>
<message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation>Non è possibile ottenere i dati sulla cartella %s. Probabilmente %s è già in esecuzione.</translation>
+ </message>
+ <message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation>Elimina tutte le transazioni dal portamonete e recupera solo quelle che fanno parte della blockchain attraverso il comando -rescan all'avvio.</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuito secondo la licenza software MIT, vedi il file COPYING incluso oppure &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
+ <source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
+ <translation>Errore caricamento %s: Non puoi abilitare HD in un portafoglio non-HD già esistente</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>Errore lettura %s! Tutte le chiavi sono state lette correttamente, ma i dati delle transazioni o della rubrica potrebbero essere mancanti o non corretti.</translation>
</message>
<message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Esegue un comando quando lo stato di una transazione del portamonete cambia (%s in cmd è sostituito da TxID)</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>Regolazione della massima differenza media di tempo dei peer consentita. L'impostazione dell'orario locale può essere impostata in avanti o indietro di questa quantità. (default %u secondi)</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>Totale massimo di commissioni (in %s) da usare in una transazione singola o di gruppo del wallet; valori troppo bassi possono abortire grandi transazioni (default: %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>
+ <translation>Per favore controllate che la data del computer e l'ora siano corrette! Se il vostro orologio è sbagliato %s non funzionerà correttamente.</translation>
+ </message>
+ <message>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
+ <translation>Per favore contribuite se ritenete %s utile. Visitate %s per maggiori informazioni riguardo il software.</translation>
+ </message>
+ <message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation>Imposta il numero di thread per la verifica degli script (da %u a %d, 0 = automatico, &lt;0 = lascia questo numero di core liberi, predefinito: %d)</translation>
</message>
@@ -1736,24 +2023,20 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Il database dei blocchi contiene un blocco che sembra provenire dal futuro. Questo può essere dovuto alla data e ora del tuo computer impostate in modo scorretto. Ricostruisci il database dei blocchi se sei certo che la data e l'ora sul tuo computer siano corrette</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>Questa versione è una compilazione pre-rilascio - usala a tuo rischio - non utilizzarla per la generazione o per applicazioni di commercio</translation>
+ <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
+ <translation>Impossibile riportare il database ad un livello pre-fork. Dovrai riscaricare tutta la blockchain</translation>
</message>
<message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<translation>Utilizza UPnP per mappare la porta in ascolto (default: 1 quando in ascolto e -proxy non è specificato)</translation>
</message>
<message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Attenzione: La rete non sembra trovarsi in pieno consenso! Alcuni minatori sembrano riscontrare problemi.</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>Attenzione: Sembra che non vi sia pieno consenso con i nostri peer! Un aggiornamento da parte tua o degli altri nodi potrebbe essere necessario.</translation>
+ <source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
+ <translation>È necessario ricostruire il database usando -reindex per cambiare -txindex</translation>
</message>
<message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Inserisce in whitelist i peer che si connettono da un dato indirizzo IP o netmask. Può essere specificato più volte.</translation>
+ <source>%s corrupt, salvage failed</source>
+ <translation>%s corrotto, recupero fallito</translation>
</message>
<message>
<source>-maxmempool must be at least %d MB</source>
@@ -1764,18 +2047,34 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Valori possibili per &lt;category&gt;:</translation>
</message>
<message>
+ <source>Append comment to the user agent string</source>
+ <translation>Aggiungi commento alla stringa dell'applicazione utente</translation>
+ </message>
+ <message>
+ <source>Attempt to recover private keys from a corrupt wallet on startup</source>
+ <translation>Prova a recuperare le chiavi private da un portafoglio corrotto all'avvio</translation>
+ </message>
+ <message>
<source>Block creation options:</source>
<translation>Opzioni creazione blocco:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Connessione ai soli nodi specificati</translation>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>Impossobile risolvere l'indirizzo -%s: '%s'</translation>
+ </message>
+ <message>
+ <source>Change index out of range</source>
+ <translation>Cambio indice fuori paramentro</translation>
</message>
<message>
<source>Connection options:</source>
<translation>Opzioni di connessione:</translation>
</message>
<message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Copyright (C) %i-%i</translation>
+ </message>
+ <message>
<source>Corrupted block database detected</source>
<translation>Rilevato database blocchi corrotto</translation>
</message>
@@ -1808,6 +2107,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Abilita pubblicazione transazione raw in &lt;address&gt;</translation>
</message>
<message>
+ <source>Enable transaction replacement in the memory pool (default: %u)</source>
+ <translation>Abilita la sostituzione della transazione nel pool della memoria (default: %u)</translation>
+ </message>
+ <message>
<source>Error initializing block database</source>
<translation>Errore durante l'inizializzazione del database dei blocchi</translation>
</message>
@@ -1816,6 +2119,22 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Errore durante l'inizializzazione dell'ambiente del database del portamonete %s!</translation>
</message>
<message>
+ <source>Error loading %s</source>
+ <translation>Errore caricamento %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation>Errore caricamento %s: Portafoglio corrotto</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation>Errore caricamento %s: il Portafoglio richiede una versione aggiornata di %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: You can't disable HD on a already existing HD wallet</source>
+ <translation>Errore caricamento %s: Non puoi disabilitare HD in un portafoglio HD già esistente</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>Errore durante il caricamento del database blocchi</translation>
</message>
@@ -1840,14 +2159,34 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Blocco genesi non corretto o non trovato. È possibile che la cartella dati appartenga ad un'altra rete.</translation>
</message>
<message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation>Test di integrità iniziale fallito. %s si arresterà.</translation>
+ </message>
+ <message>
<source>Invalid -onion address: '%s'</source>
<translation>Indirizzo -onion non valido: '%s'</translation>
</message>
<message>
+ <source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
+ <translation>Importo non valido per -%s=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
+ <translation>Importo non valido per -fallbackfee=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
<source>Keep the transaction memory pool below &lt;n&gt; megabytes (default: %u)</source>
<translation>Mantieni la memory pool delle transazioni al di sotto di &lt;n&gt; megabytes (default: %u)</translation>
</message>
<message>
+ <source>Loading banlist...</source>
+ <translation>Caricamento bloccati...</translation>
+ </message>
+ <message>
+ <source>Location of the auth cookie (default: data dir)</source>
+ <translation>Posizione del cookie di aiutorizzazione (default: data dir)</translation>
+ </message>
+ <message>
<source>Not enough file descriptors available.</source>
<translation>Non ci sono abbastanza descrittori di file disponibili.</translation>
</message>
@@ -1856,6 +2195,14 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Connessione ai soli nodi appartenenti alla rete &lt;net&gt; (ipv4, ipv6 o Tor)</translation>
</message>
<message>
+ <source>Print this help message and exit</source>
+ <translation>Mostra questo messaggio di aiuto ed esci</translation>
+ </message>
+ <message>
+ <source>Print version and exit</source>
+ <translation>Mostra la versione ed esci</translation>
+ </message>
+ <message>
<source>Prune cannot be configured with a negative value.</source>
<translation>La modalità prune non può essere configurata con un valore negativo.</translation>
</message>
@@ -1864,6 +2211,18 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>La modalità prune è incompatibile con l'opzione -txindex.</translation>
</message>
<message>
+ <source>Rebuild chain state and block index from the blk*.dat files on disk</source>
+ <translation>Ricostruisci lo stato della catena e l'indice dei blocchi partendo dai file blk*.dat presenti sul disco</translation>
+ </message>
+ <message>
+ <source>Rebuild chain state from the currently indexed blocks</source>
+ <translation>Ricrea l'indice della catena dei blocchi partendo da quelli già indicizzati</translation>
+ </message>
+ <message>
+ <source>Rewinding blocks...</source>
+ <translation>Verifica blocchi...</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>Imposta la dimensione della cache del database in megabyte (%d a %d, predefinito: %d)</translation>
</message>
@@ -1876,6 +2235,14 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Specifica il file del portamonete (all'interno della cartella dati)</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation>Il codice sorgente è disponibile in %s</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation>Impossibile collegarsi a %s su questo computer. Probabilmente %s è già in esecuzione.</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Ignorata opzione -benchmark non supportata, utilizzare -debug=bench.</translation>
</message>
@@ -1908,6 +2275,14 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Il portamonete %s si trova al di fuori dalla cartella dati %s</translation>
</message>
<message>
+ <source>Wallet debugging/testing options:</source>
+ <translation>Opzioni di Debug/Test del portafoglio:</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>Il portamonete necessita di essere riscritto: riavviare %s per completare</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Opzioni portamonete:</translation>
</message>
@@ -1956,10 +2331,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Dimensione massima dei dati in transazioni di trasporto dati che saranno trasmesse ed incluse nei blocchi (predefinito: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Ottiene gli indirizzi dei peer attraverso interrogazioni DNS, in caso di scarsa disponibilità (predefinito: 1 a meno che -connect non sia specificato)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Randomizza le credenziali per ogni connessione proxy. Permette la Tor stream isolation (predefinito: %u)</translation>
</message>
@@ -1972,8 +2343,8 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>L'importo della transazione risulta troppo basso per l'invio una volta dedotte le commissioni.</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso del Toolkit OpenSSL &lt;https://www.openssl.org/&gt;, software crittografico scritto da Eric Young e software UPnP scritto da Thomas Bernard.</translation>
+ <source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
+ <translation>Usa la generazione gerarchica deterministica (HD) della chiave dopo BIP32. Valido solamente durante la creazione del portafoglio o al primo avvio</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>
@@ -2084,10 +2455,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Importo transazione troppo piccolo</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Gli importi della transazione devono essere positivi</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transazione troppo grande in base alla policy sulle commissioni</translation>
</message>
@@ -2112,6 +2479,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Attenzione</translation>
</message>
<message>
+ <source>Warning: unknown new rules activated (versionbit %i)</source>
+ <translation>Attenzione: nuove regole non conosciute attivate (versionbit %i)</translation>
+ </message>
+ <message>
<source>Whether to operate in a blocks only mode (default: %u)</source>
<translation>Imposta se operare in modalità solo blocchi (default: %u)</translation>
</message>
@@ -2148,14 +2519,14 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>-maxtxfee è impostato molto alto! Commissioni così alte possono venir pagate anche su una singola transazione.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee è impostato su un valore molto elevato. Questa è la commissione che si paga quando si invia una transazione.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Non mantenere le transazioni nella mempool più a lungo di &lt;n&gt; ore (default: %u)</translation>
</message>
<message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Byte equivalenti per ottimizzazione segnale dedicati a ritrasmissione ed estrazione (default: %u)</translation>
+ </message>
+ <message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation>Le commissioni (in %s/kB) inferiori a questo valore sono considerate pari a zero per la creazione della transazione (default: %s)</translation>
</message>
@@ -2192,12 +2563,20 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Argomento -socks non supportato. Non è più possibile impostare la versione SOCKS, solamente i proxy SOCKS5 sono supportati.</translation>
</message>
<message>
+ <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
+ <translation>Argomento non supportato -whitelistalwaysrelay è stato ignorato, utilizzare -whitelistrelay e/o -whitelistforcerelay.</translation>
+ </message>
+ <message>
<source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)</source>
<translation>Usa un proxy SOCKS5 a parte per raggiungere i peer attraverso gli hidden services di Tor (predefinito: %s)</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. This option can be specified multiple times</source>
- <translation>Username e hash password per connessioni JSON-RPC. Il campo &lt;userpw&gt; utilizza il formato: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Uno script python standard è incluso in share/rpcuser. Questa opzione può essere specificata più volte</translation>
+ <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
+ <translation>Attenzione: si stanno minando versioni sconocsiute di blocchi! E' possibile che siano attive regole sconosciute</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>Attenzione: file del Portafoglio corrotto, dati recuperati! %s originale salvato come %s in %s; se il saldo o le transazioni non sono corrette effettua un ripristino da un backup.</translation>
</message>
<message>
<source>(default: %s)</source>
@@ -2260,8 +2639,8 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Imposta la dimensione del pool di chiavi a &lt;n&gt; (predefinito: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Imposta la dimensione minima del blocco in byte (predefinito: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Imposta la dimensione massima del blocco BIP141 (default: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
diff --git a/src/qt/locale/bitcoin_it_IT.ts b/src/qt/locale/bitcoin_it_IT.ts
index f89f4bdc48..09d40497fa 100644
--- a/src/qt/locale/bitcoin_it_IT.ts
+++ b/src/qt/locale/bitcoin_it_IT.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>Cancella</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -56,10 +59,18 @@
<source>Repeat new passphrase</source>
<translation>Ripeti nuova passphrase</translation>
</message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Attenzione: Il tasto blocco delle maiuscole è attivo!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
<message>
+ <source>IP/Netmask</source>
+ <translation>IP/Netmask</translation>
+ </message>
+ <message>
<source>Banned Until</source>
<translation>bannato fino </translation>
</message>
@@ -87,6 +98,9 @@
<name>Intro</name>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -96,12 +110,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -111,12 +134,18 @@
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -129,12 +158,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts
index 4948cc3067..f81818896f 100644
--- a/src/qt/locale/bitcoin_ja.ts
+++ b/src/qt/locale/bitcoin_ja.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>削除(&amp;D)</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;C)</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>これらは支払いを受け取るためのビットコインアドレスです。トランザクションごとに新しい受け取り用アドレスを作成することが推奨されます。</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 (*.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>
+ <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>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>新しいパスフレーズをもう一度</translation>
</message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>ウォレットの新しいパスフレーズを入力してください。&lt;br/&gt;&lt;b&gt;10文字以上のランダムな文字&lt;/b&gt;で構成されたものか、&lt;b&gt;8単語以上の単語&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;あなたの 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 をいますぐ終了します。ウォレットの暗号化では、コンピュータに感染したマルウェアなどによるビットコインの盗難から完全に守ることはできないことにご注意ください。</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>
@@ -159,6 +318,22 @@
<translation>URI を開く (&amp;U)...</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>
@@ -270,34 +445,10 @@
<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>
</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>
<message>
<source>%1 behind</source>
<translation>%1 遅延</translation>
@@ -335,6 +486,10 @@
<translation>%1 クライアント</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>ピアに接続しています...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>追跡中...</translation>
</message>
@@ -377,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;</translation>
</message>
@@ -384,6 +547,10 @@
<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;</translation>
</message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>致命的なエラーが発生しました。Bitcoin は安全に継続することができず終了するでしょう。</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -404,10 +571,6 @@
<translation>総額:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>優先度:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>手数料:</translation>
</message>
@@ -460,8 +623,84 @@
<translation>検証済み</translation>
</message>
<message>
- <source>Priority</source>
- <translation>優先度</translation>
+ <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>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 satoshi 前後ずれることがあります。</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>
@@ -486,6 +725,38 @@
<source>&amp;Address</source>
<translation>アドレス帳 (&amp;A)</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>
+ <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>
@@ -609,6 +880,57 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <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>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>未知。ヘッダを同期しています (%1)...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -626,6 +948,10 @@
<source>Select payment request file</source>
<translation>支払いリクエストファイルを選択してください</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>開きたい支払いリクエストファイルを選択してください</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -938,6 +1264,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>支払いのリクエストのエラーです</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Bitcoin を起動できません: click-to-pay handler</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>URI の操作</translation>
+ </message>
+ <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 を解析できません! これは無効な Bitcoin アドレスあるいや不正な形式の 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>
<source>User Agent</source>
@@ -948,8 +1365,12 @@
<translation>ノード・サービス</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Ping時間</translation>
+ <source>NodeId</source>
+ <translation>ノードID</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
</message>
</context>
<context>
@@ -990,6 +1411,72 @@
<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>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 はまだ安全に終了していません...</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <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 という記法のみを利用してください。</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>エラー: %1</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <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>
@@ -1150,6 +1637,10 @@
<translation>Ping待ち</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>最小 Ping</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>時間オフセット</translation>
</message>
@@ -1194,14 +1685,6 @@
<translation>コンソールをクリア</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>ノードを切断する (&amp;D)</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>ノードをbanする:</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1時間 (&amp;H)</translation>
</message>
@@ -1218,8 +1701,16 @@
<translation>1年 (&amp;Y)</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>ノードのbanを解除する (&amp;U)</translation>
+ <source>&amp;Disconnect</source>
+ <translation>切断 (&amp;D)</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Banする:</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>Banを解除する (&amp;U)</translation>
</message>
<message>
<source>Welcome to the %1 RPC console.</source>
@@ -1234,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 B</translation>
</message>
@@ -1352,6 +1851,22 @@
<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>
@@ -1371,6 +1886,73 @@
<source>&amp;Save Image...</source>
<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>
+ <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>QR コード用の URI エンコードでエラー。</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>
+ <message>
+ <source>Requested</source>
+ <translation>要求</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1407,10 +1989,6 @@
<translation>総額:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>優先度:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>手数料:</translation>
</message>
@@ -1479,10 +2057,6 @@
<translation>(スマート手数料はまだ初期化されていません。これにはおおよそ数ブロックほどかかります……)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>検証時間:</translation>
- </message>
- <message>
<source>normal</source>
<translation>普通</translation>
</message>
@@ -1507,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>
@@ -1522,6 +2100,126 @@
<source>S&amp;end</source>
<translation>送金 (&amp;E)</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>%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>警告:無効なBitcoinアドレスです</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>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1601,6 +2299,17 @@
<source>Memo:</source>
<translation>メモ:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>アドレス帳に追加するには、このアドレスのラベルを入力します</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>はい</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1699,6 +2408,58 @@
<source>Reset all verify message fields</source>
<translation>入力項目の内容をすべて消去します</translation>
</message>
+ <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>
@@ -1715,11 +2476,460 @@
</message>
</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>
+ <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>
+ <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 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>(n/a)</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>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>ユーザ定義のトランザクションの意図や目的。</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>生トランザクションをコピー</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 (*.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>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>エクスポートに失敗しました</translation>
+ </message>
+ <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>
@@ -1729,6 +2939,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>ウォレットがロードされていません</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>コインを送る</translation>
+ </message>
+</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>
+ <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>
<source>Options:</source>
@@ -1751,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>
@@ -1763,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>
@@ -1791,10 +3058,6 @@
<translation>HTTPサーバを開始できませんでした。詳細はデバッグログをご確認ください。</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>外部からの接続を許可 (初期値: -proxy または -connect を使用していない場合は1)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin のコア</translation>
</message>
@@ -1803,10 +3066,6 @@
<translation>%s の開発者</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee が高すぎます!これは手数料の推定機能が利用できない場合に支払うトランザクション手数料です。</translation>
- </message>
- <message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
<translation>十分なデータが蓄積されていない場合に手数料推定機能が利用する手数料レート (%s/kB) (デフォルト: %s)</translation>
</message>
@@ -1827,10 +3086,6 @@
<translation>ウォレットの全トランザクションを削除し、これらを-rescanオプションを用いることで起動時にブロックチェインのデータのみからリカバリします。</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>MITソフトウェアライセンスのもとで配布されています。付属のCOPYINGファイルまたは&lt;http://www.opensource.org/licenses/mit-license.php&gt;を参照してください。</translation>
- </message>
- <message>
<source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
<translation>%s の読み込みエラー: 非HDウォレットが既に存在するため、HDウォレットを有効化できません</translation>
</message>
@@ -1843,8 +3098,12 @@
<translation>ウォレットの取引を変更する際にコマンドを実行 (cmd の %s は TxID に置換される)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>ホワイトリストのピアから受け取ったトランザクションに関しては、たとえローカルの中継ポリシーに違反しているとしても中継を行うようにする (デフォルト: %d)</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、テストネット: %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>
@@ -1863,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>
@@ -1883,16 +3150,20 @@
<translation>リスン ポートの割当に UPnP を使用 (初期値: リスン中および-proxyが指定されていない場合は1)</translation>
</message>
<message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>警告: ネットワークは完全に同意しないみたいです。マイナーは何かの問題を経験してるみたいなんです。</translation>
+ <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>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>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation>ウォレットがmempoolチェーン制限数を超えてトランザクションを作らないようにする (初期値: %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>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>与えられたネットマスクやIPアドレスから接続を行う、ホワイトリストのピア。複数回指定できます。</translation>
+ <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>
@@ -1927,12 +3198,12 @@
<translation>-%s アドレス '%s' を解決できません</translation>
</message>
<message>
- <source>Change index out of range</source>
- <translation>おつりのインデックスが範囲外です</translation>
+ <source>Chain selection options:</source>
+ <translation>チェイン選択オプション:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>指定したノードだけに接続</translation>
+ <source>Change index out of range</source>
+ <translation>おつりのインデックスが範囲外です</translation>
</message>
<message>
<source>Connection options:</source>
@@ -2056,10 +3327,6 @@
<translation>認証クッキーの場所 (デフォルト: )</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>中継や採掘を行ってもよい、sigopあたりの最小バイト数 (デフォルト: %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>使用可能なファイルディスクリプタが不足しています。</translation>
</message>
@@ -2100,10 +3367,6 @@
<translation>データベースのキャッシュサイズをメガバイトで設定 (%dから%d。初期値: %d)</translation>
</message>
<message>
- <source>Set maximum block cost (default: %d)</source>
- <translation>最大ブロックコストを設定 (初期値: %d)</translation>
- </message>
- <message>
<source>Set maximum block size in bytes (default: %d)</source>
<translation>最大ブロックサイズをバイトで設定 (初期値: %d)</translation>
</message>
@@ -2136,6 +3399,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>
@@ -2208,10 +3475,6 @@
<translation>中継および採掘を行う際の、データ運送トランザクションの中のデータの最大サイズ (初期値: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>保有するピアアドレスが少ない場合、DNS ルックアップによりピアアドレスを問い合わせる (-connect を使っていない場合の初期値: 1)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>認証情報をプロキシー接続ごとにランダム化する。これによりTorストリーム分離をすることができます (規定値: %u)</translation>
</message>
@@ -2224,10 +3487,6 @@
<translation>手数料差引後のトランザクションの金額が小さすぎるため、送金できません。</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>この製品はOpenSSLプロジェクトにより開発されたソフトウェアをOpenSSLツールキットとして利用しています &lt;https://www.openssl.org/&gt;。また、Eric Young氏により開発された暗号ソフトウェア、Thomas Bernard氏により書かれたUPnPソフトウェアを用いています。</translation>
- </message>
- <message>
<source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
<translation>BIP32 に従った階層的決定性鍵生成方式 (HD) を利用します。ウォレットの生成時ないし最初に起動した時にのみ有効です。</translation>
</message>
@@ -2340,10 +3599,6 @@
<translation>取引の額が小さ過ぎます</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>取引の額は0より大きくしてください</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>手数料ポリシーに対してトランザクションが大きすぎます</translation>
</message>
@@ -2408,18 +3663,22 @@
<translation>-maxtxfee が非常に高く設定されています!ひとつのトランザクションでこの量の手数料が支払われてしまうことがあります。</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee が非常に高く設定されています! これは取引を送信する場合に支払う取引手数料です。</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>mempool内でトランザクションを &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>
@@ -2436,10 +3695,26 @@
<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>非冗長モードで返却する生トランザクションやブロックの16進数表現のシリアライゼーションフォーマットを非 segwit (0) または segwit (1) のものに設定する (デフォルト: %d)</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation>Bloomフィルタによる、ブロックおよびトランザクションのフィルタリングを有効化する (初期値: %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プロジェクトにより開発されたソフトウェアをOpenSSLツールキット %s として利用しています &lt;https://www.openssl.org/&gt;。また、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>
<translation>ネットワークバージョン文字 (%i) の長さが最大の長さ (%i) を超えています。UAコメントの数や長さを削減してください。</translation>
</message>
@@ -2460,10 +3735,6 @@
<translation>Tor 秘匿サービスを通し、別々の SOCKS5 プロキシを用いることでピアに到達する (初期値: %s)</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. 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 内に含まれています。このオプションは複数回指定できます。</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>警告: 未知のバージョンのブロックが採掘されました。未知のルールが導入された可能性があります</translation>
</message>
@@ -2472,6 +3743,14 @@
<translation>警告: ウォレットファイルが破損していましたのでデータを復旧しました!元の %s は %s として %s に保存されました; 残高やトランザクションが正しくない場合にはバックアップから復元してください。</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>ホワイトリストとして登録するピアノ、接続元の 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>
@@ -2492,6 +3771,10 @@
<translation>無効な -proxy アドレス: '%s'</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>鍵プールが枯渇しました。まずはじめに keypoolrefill を呼び出してください</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>&lt;port&gt; で JSON-RPC 接続をリスン (初期値: %u、testnet は %u)</translation>
</message>
@@ -2528,12 +3811,16 @@
<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>key pool のサイズを &lt;n&gt; (初期値: %u) にセット</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>最小ブロックサイズをバイトで設定 (初期値: %u)</translation>
+ <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>
@@ -2556,10 +3843,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>トランザクションの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>
<translation>-onlynet で指定された '%s' は未知のネットワークです</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts
index 80508be8ee..14378ebea1 100644
--- a/src/qt/locale/bitcoin_ka.ts
+++ b/src/qt/locale/bitcoin_ka.ts
@@ -37,7 +37,10 @@
<source>&amp;Delete</source>
<translation>&amp;წაშლა</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -56,7 +59,7 @@
<source>Repeat new passphrase</source>
<translation>გაიმეორეთ ახალი ფრაზა-პაროლი</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -235,14 +238,6 @@
<translation>საკომანდო სტრიქონის ოპ&amp;ციები</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>ბლოკების წყარო მიუწვდომელია...</translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 და %2</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 გავლილია</translation>
</message>
@@ -290,7 +285,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -306,10 +301,6 @@
<translation>თანხა:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>პრიორიტეტი:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>საკომისიო:</translation>
</message>
@@ -349,11 +340,7 @@
<source>Confirmed</source>
<translation>დადასტურებულია</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>პრიორიტეტი</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -376,7 +363,7 @@
<source>&amp;Address</source>
<translation>მის&amp;ამართი</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -439,6 +426,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>ფორმა</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>ბოლო ბლოკის დრო</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -456,7 +454,7 @@
<source>Select payment request file</source>
<translation>გადახდის მოთხოვნის ფაილის არჩევა</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -640,6 +638,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -660,6 +661,16 @@
<source>N/A</source>
<translation>მიუწვდ.</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 და %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -842,7 +853,7 @@
<source>Remove</source>
<translation>წაშლა</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -861,7 +872,10 @@
<source>&amp;Save Image...</source>
<translation>გამო&amp;სახულების შენახვა...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -897,10 +911,6 @@
<translation>თანხა:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>პრიორიტეტი:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>საკომისიო:</translation>
</message>
@@ -952,7 +962,7 @@
<source>S&amp;end</source>
<translation>გაგ&amp;ზავნა</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1011,7 +1021,10 @@
<source>Memo:</source>
<translation>შენიშვნა:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1089,7 +1102,7 @@
<source>Reset all verify message fields</source>
<translation>ვერიფიკაციის ყველა ველის წაშლა</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1105,16 +1118,34 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>ტრანსაქციის დაწვრილებითი აღწერილობა</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1141,10 +1172,6 @@
<translation>რეზიდენტულად გაშვება და კომანდების მიღება</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>გარედან შეერთებების დაშვება (ნაგულისხმევი: 1 თუ არ გამოიყენება -proxy ან -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1157,18 +1184,6 @@
<translation>კომანდის შესრულება საფულის ტრანსაქციის ცვლილებისას (%s კომანდაში ჩანაცვლდება TxID-ით)</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>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>&lt;category&gt; can be:</source>
<translation>&lt;category&gt; შეიძლება იყოს:</translation>
</message>
@@ -1177,10 +1192,6 @@
<translation>ბლოკის შექმნის ოპციები:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>შეერთება მხოლოდ მითითებულ კვანძ(ებ)თან</translation>
- </message>
- <message>
<source>Corrupted block database detected</source>
<translation>შენიშნულია ბლოკთა ბაზის დაზიანება</translation>
</message>
@@ -1281,10 +1292,6 @@
<translation>ტრანსაქციების რაოდენობა ძალიან ცოტაა</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>ტრანსაქციების რაოდენობა დადებითი რიცხვი უნდა იყოს</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>ტრანსაქცია ძალიან დიდია</translation>
</message>
diff --git a/src/qt/locale/bitcoin_kk_KZ.ts b/src/qt/locale/bitcoin_kk_KZ.ts
index ff02521264..2c9d228401 100644
--- a/src/qt/locale/bitcoin_kk_KZ.ts
+++ b/src/qt/locale/bitcoin_kk_KZ.ts
@@ -25,7 +25,10 @@
<source>&amp;Delete</source>
<translation>Жою</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -40,7 +43,7 @@
<source>Repeat new passphrase</source>
<translation>Жаңа құпия сөзді қайта енгізу</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -90,26 +93,6 @@
<source>&amp;Help</source>
<translation>Көмек</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>
<message>
<source>%1 behind</source>
<translation>%1 қалмады</translation>
@@ -138,10 +121,6 @@
<translation>Саны</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Басымдық</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Комиссия</translation>
</message>
@@ -169,11 +148,7 @@
<source>Confirmed</source>
<translation>Растық</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Басымдық</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -184,7 +159,7 @@
<source>&amp;Address</source>
<translation>Адрес</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -199,6 +174,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -212,6 +190,9 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -220,6 +201,16 @@
<source>Amount</source>
<translation>Саны</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 немесе %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -239,16 +230,15 @@
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Amount:</source>
<translation>Саны</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Басымдық</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Комиссия:</translation>
</message>
@@ -269,6 +259,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -281,12 +274,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Information</source>
diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts
index 012632c0e0..9b5c1c077e 100644
--- a/src/qt/locale/bitcoin_ko_KR.ts
+++ b/src/qt/locale/bitcoin_ko_KR.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>삭제(&amp;D)</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;H)</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>계좌 복사(&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>
+ <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>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>새로운 암호 재확인</translation>
</message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>지갑에 새로운 비밀문구를 입력하세요.&lt;br/&gt;비밀문구를 &lt;b&gt;열 개 이상의 무작위 글자&lt;/b&gt; 혹은 &lt;b&gt;여덟개 이상의 단어로&lt;b&gt; 정하세요.</translation>
+ </message>
+ <message>
+ <source>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>
@@ -111,6 +270,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>&amp;Qt 정보</translation>
</message>
@@ -123,6 +290,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>
@@ -251,32 +422,16 @@
<translation><numerusform>비트코인 네트워크에 %n개의 연결이 활성화되어 있습니다.</numerusform></translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>사용 가능한 블록이 없습니다...</translation>
- </message>
- <message numerus="yes">
- <source>Processed %n block(s) of transaction history.</source>
- <translation><numerusform>%n 블럭 만큼의 거래 기록이 처리됨.</numerusform></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>
+ <source>Indexing blocks on disk...</source>
+ <translation>디스크에서 블록 색인중...</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 그리고 %2</translation>
+ <source>Processing blocks on disk...</source>
+ <translation>디스크에서 블록 처리중...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n년</numerusform></translation>
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>%n 블럭 만큼의 거래 기록이 처리됨.</numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -307,6 +462,14 @@
<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>Catching up...</source>
<translation>블록 따라잡기...</translation>
</message>
@@ -356,7 +519,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>지갑이 암호화 되었고 현재 잠겨져 있습니다</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -376,10 +539,6 @@
<translation>금액:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>우선순위:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>수수료:</translation>
</message>
@@ -432,8 +591,80 @@
<translation>확인됨</translation>
</message>
<message>
- <source>Priority</source>
- <translation>우선순위</translation>
+ <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>bytes 복사</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 사토시(s)가 변할 수 있습니다.</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>
@@ -458,6 +689,38 @@
<source>&amp;Address</source>
<translation>주소(&amp;A)</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>
+ <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>
@@ -493,6 +756,10 @@
<translation>(%1-비트)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>%1 정보(&amp;A)</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>명령줄 옵션</translation>
</message>
@@ -528,7 +795,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>GUI를 통해 수정된 모든 설정을 초기화</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -536,6 +807,18 @@
<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>%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>
+ <message>
<source>Use the default data directory</source>
<translation>기본 데이터 폴더를 사용하기</translation>
</message>
@@ -561,6 +844,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>유형</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>최종 블럭 시각</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>숨기기</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -578,6 +876,10 @@
<source>Select payment request file</source>
<translation>지불 요청 파일을 선택하세요</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>지불 요청 파일을 열기 위해서 선택하세요</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -590,6 +892,14 @@
<translation>메인(&amp;M)</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>시스템 로그인시 %1 시작(&amp;S)</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>데이터베이스 캐시 크기(&amp;D)</translation>
</message>
@@ -691,7 +1001,7 @@
</message>
<message>
<source>Port of the proxy (e.g. 9050)</source>
- <translation>프록시의 포트번호입니다(예: 9050)</translation>
+ <translation>프록시의 포트번호입니다 (예: 9050)</translation>
</message>
<message>
<source>Used for reaching peers via:</source>
@@ -726,6 +1036,14 @@
<translation>창(&amp;W)</translation>
</message>
<message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>시스템 트레이 로 부터 아이콘 숨기기(&amp;H)</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>
@@ -746,6 +1064,10 @@
<translation>사용자 인터페이스 언어(&amp;L):</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;U):</translation>
</message>
@@ -870,6 +1192,21 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>지불 요청 오류</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>비트코인을 시작할 수 없습니다: 지급제어기를 클릭하시오</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>URI 핸들링</translation>
+ </message>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -879,11 +1216,7 @@
<source>Node/Service</source>
<translation>노드/서비스</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Ping 시간</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -922,7 +1255,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 그리고 %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -950,6 +1293,10 @@
<translation>사용 중인 BerkeleyDB 버전</translation>
</message>
<message>
+ <source>Datadir</source>
+ <translation>데이터 폴더</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>시작 시간</translation>
</message>
@@ -1034,6 +1381,18 @@
<translation>유저 에이전트</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>%1 디버그 로그파일을 현재 데이터 폴더에서 엽니다. 용량이 큰 로그 파일들은 몇 초가 걸릴 수 있습니다.</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>
@@ -1110,14 +1469,6 @@
<translation>콘솔 초기화</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>끊긴 노드(&amp;D)</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>추방된 노드:</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1시간(&amp;H)</translation>
</message>
@@ -1134,8 +1485,8 @@
<translation>1년(&amp;Y)</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>노드 추방 취소(&amp;U)</translation>
+ <source>Welcome to the %1 RPC console.</source>
+ <translation>%1 RPC 콘솔에 오신걸 환영합니다</translation>
</message>
<message>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
@@ -1264,6 +1615,14 @@
<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>
@@ -1283,7 +1642,30 @@
<source>&amp;Save Image...</source>
<translation>이미지 저장(&amp;S)...</translation>
</message>
-</context>
+ <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>
<message>
@@ -1319,10 +1701,6 @@
<translation>거래액:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>우선순위:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>수수료:</translation>
</message>
@@ -1391,10 +1769,6 @@
<translation>(Smart fee가 아직 초기화되지 않았습니다. 블록 분석이 완료될 때 까지 기다려주십시오...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>승인 시간:</translation>
- </message>
- <message>
<source>normal</source>
<translation>일반</translation>
</message>
@@ -1434,6 +1808,38 @@
<source>S&amp;end</source>
<translation>보내기(&amp;E)</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>bytes 복사</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>
@@ -1443,11 +1849,11 @@
</message>
<message>
<source>Pay &amp;To:</source>
- <translation>송금할 대상(&amp;T) : </translation>
+ <translation>송금할 대상(&amp;T):</translation>
</message>
<message>
<source>&amp;Label:</source>
- <translation>라벨(&amp;L)</translation>
+ <translation>라벨(&amp;L):</translation>
</message>
<message>
<source>Choose previously used address</source>
@@ -1507,16 +1913,23 @@
</message>
<message>
<source>Pay To:</source>
- <translation>송금할 대상 : </translation>
+ <translation>송금할 대상:</translation>
</message>
<message>
<source>Memo:</source>
<translation>메모:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down...</source>
+ <translation>%1이 종료 중입니다...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation>창이 사라지기 전까지 컴퓨터를 끄지마시오.</translation>
</message>
@@ -1607,7 +2020,7 @@
<source>Reset all verify message fields</source>
<translation>모든 검증 메시지 필드 재설정</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1623,11 +2036,152 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</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>
+<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>Received with</source>
+ <translation>받은 주소</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>보낸 주소</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(라벨 없음)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Received with</source>
+ <translation>받은 주소</translation>
+ </message>
+ <message>
+ <source>Sent to</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>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>
+ <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>
@@ -1637,6 +2191,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>지갑 불러오기가 안됩니다.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>코인 보내기</translation>
+ </message>
+</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>
+ <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>
<source>Options:</source>
@@ -1671,10 +2274,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>
@@ -1699,16 +2298,12 @@
<translation>HTTP 서버를 시작할 수 없습니다. 자세한 사항은 디버그 로그를 확인 하세요.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>외부 접속을 승인합니다</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>비트코인 코어</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee은 너무 높습니다! 이것은 수수료 예측을 이용할 수 없을 때 지불되는 트랜잭션 수수료입니다.</translation>
+ <source>The %s developers</source>
+ <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>
@@ -1723,20 +2318,36 @@
<translation>선택된 주소로 고정하며 항상 리슨(Listen)합니다. IPv6 프로토콜인 경우 [host]:port 방식의 명령어 표기법을 사용합니다.</translation>
</message>
<message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation>%s 데이터 디렉토리에 락을 걸 수 없었습니다. %s가 이미 실행 중인 것으로 보입니다.</translation>
+ </message>
+ <message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation>시작시 모든 지갑 트랜잭션을 삭제하고 -rescan을 통하여 블록체인만 복구합니다.</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>MIT 소프트웨어 라이센스에 따라 배포됩니다. 동봉된 파일 혹은 &lt;http://www.opensource.org/licenses/mit-license.php&gt;를 참조하세요.</translation>
+ <source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
+ <translation>%s 불러오기 오류: 비-HD 지갑이 존재하는 상태에서 HD 지갑을 활성화 할 수 없습니다</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>%s 불러오기 오류: 주소 키는 모두 정확하게 로드되었으나 거래 데이터와 주소록 필드에서 누락이나 오류가 존재할 수 있습니다.</translation>
</message>
<message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>지갑 거래가 바뀌면 명령을 실행합니다.(%s 안의 명령어가 TxID로 바뀝니다)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>피어들이 로컬 중계 정책을 위반하더라도 화이트 리스트에 포함된 피어인경우 강제로 중계하기 (기본값: %d)</translation>
+ <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>
+ </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>
+ <translation>컴퓨터의 날짜와 시간이 올바른지 확인하십시오! 시간이 잘못되면 %s은 제대로 동작하지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</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>
@@ -1747,24 +2358,20 @@
<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>
+ <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
+ <translation>데이터베이스를 포크 전 상태로 돌리지 못했습니다. 블록체인을 다시 다운로드 해주십시오.</translation>
</message>
<message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<translation>리슨(Listen) 포트를 할당하기 위해 UPnP 사용 (기본값: 열려있거나 -proxy 옵션을 사용하지 않을 시 1)</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>
+ <source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
+ <translation>-txindex를 바꾸기 위해서는 -reindex-chainstate를 사용해서 데이터베이스를 재구성해야 합니다. </translation>
</message>
<message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>설정된 넷마스크 혹은 IP 주소로 화이트리스트에 포함된 피어에 접속합니다. 이 설정은 복수로 지정 할 수 있습니다.</translation>
+ <source>%s corrupt, salvage failed</source>
+ <translation>%s 손상되었고 복구가 실패하였습니다</translation>
</message>
<message>
<source>-maxmempool must be at least %d MB</source>
@@ -1779,18 +2386,26 @@
<translation>사용자 에이전트 문자열에 코멘트 첨부</translation>
</message>
<message>
+ <source>Attempt to recover private keys from a corrupt wallet on startup</source>
+ <translation>시작시 망가진 wallet.dat에서 개인키 복원을 시도합니다</translation>
+ </message>
+ <message>
<source>Block creation options:</source>
<translation>블록 생성 옵션:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>지정된 노드에만 연결하기</translation>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>%s 주소를 확인할 수 없습니다: '%s'</translation>
</message>
<message>
<source>Connection options:</source>
<translation>연결 설정 : </translation>
</message>
<message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Copyright (C) %i-%i</translation>
+ </message>
+ <message>
<source>Corrupted block database detected</source>
<translation>손상된 블록 데이터베이스가 감지되었습니다</translation>
</message>
@@ -1835,6 +2450,22 @@
<translation>지갑 데이터베이스 환경 초기화하는데 오류 %s</translation>
</message>
<message>
+ <source>Error loading %s</source>
+ <translation>%s 불러오기 오류</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation>%s 불러오기 오류: 지갑 오류</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation>%s 불러오기 에러: 지갑은 새 버전의 %s이 필요합니다</translation>
+ </message>
+ <message>
+ <source>Error loading %s: You can't disable HD on a already existing HD wallet</source>
+ <translation>%s 불러오기 오류: 이미 HD 지갑이 존재하는 상태에서 HD 지갑을 비활성화 할 수 없습니다</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>블록 데이터베이스를 불러오는데 오류</translation>
</message>
@@ -1859,10 +2490,18 @@
<translation>올바르지 않거나 생성된 블록을 찾을 수 없습니다. 잘못된 네트워크 자료 디렉토리?</translation>
</message>
<message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation>무결성 확인 초기화가 실패했습니다. %s가 종료됩니다.</translation>
+ </message>
+ <message>
<source>Invalid -onion address: '%s'</source>
<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>
@@ -1871,12 +2510,12 @@
<translation>트랜잭션 메모리 풀의 용량을 &lt;n&gt;메가바이트 아래로 유지하기 (기본값: %u)</translation>
</message>
<message>
- <source>Location of the auth cookie (default: data dir)</source>
- <translation>인증 쿠키의 위치 (기본값: data dir)</translation>
+ <source>Loading banlist...</source>
+ <translation>추방리스트를 불러오는 중...</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>중계 및 채굴을 할 때 트랜잭션에서의 sigop 당 데이터의 최소 크기 (기본값: %u)</translation>
+ <source>Location of the auth cookie (default: data dir)</source>
+ <translation>인증 쿠키의 위치 (기본값: data dir)</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -1887,6 +2526,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>
@@ -1899,6 +2542,18 @@
<translation>블록 축소 모드는 -txindex와 호환되지 않습니다.</translation>
</message>
<message>
+ <source>Rebuild chain state and block index from the blk*.dat files on disk</source>
+ <translation>현재의 blk*.dat 파일들로부터 블록체인 색인을 재구성합니다.</translation>
+ </message>
+ <message>
+ <source>Rebuild chain state from the currently indexed blocks</source>
+ <translation>현재 색인 된 블록들로부터 블록체인을 재구성합니다.</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>
@@ -1911,6 +2566,14 @@
<translation>데이터 폴더 안에 지갑 파일을 선택하세요.</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation>소스코드는 %s 에서 확인하실 수 있습니다.</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation>이 컴퓨터의 %s에 바인딩 할 수 없습니다. 아마도 %s이 실행중인 것 같습니다.</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>지원하지 않는 인수 -benchmark 은 무시됩니다, -debug=bench 형태로 사용하세요.</translation>
</message>
@@ -1947,6 +2610,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>
@@ -1995,10 +2662,6 @@
<translation>중계 및 채굴을 할 때 데이터 운송 트랜잭션에서 데이터의 최대 크기 (기본값: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>DNS lookup를 통해 피어 주소에 대한 쿼리 보내기 (기본값: 1 -connect 예외)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>인증정보를 프록시 연결마다 무작위로 합니다. 이는 Tor 스트림을 격리시킬 수 있습니다 (기본값: %u)</translation>
</message>
@@ -2011,10 +2674,6 @@
<translation>거래액이 수수료를 지불하기엔 너무 작습니다</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>이 프로그램에는 OpenSSL 툴킷&lt;https://www.openssl.org/&gt; 사용 목적으로 개발한 OpenSSL 프로젝트를 포함하고 있으며, 암호화 프로그램은 Eric Young이, UPnP 프로그램은 Thomas Bernard가 작성했습니다.</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>
</message>
@@ -2123,10 +2782,6 @@
<translation>거래액이 너무 적습니다</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>거래액은 반드시 정수여야합니다.</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>수수료 정책에 비해 트랜잭션이 너무 큽니다</translation>
</message>
@@ -2187,10 +2842,6 @@
<translation>-maxtxfee값이 너무 큽니다! 하나의 트랜잭션에 너무 큰 수수료가 지불 됩니다.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee값이 너무 큽니다! 이 값은 송금할때 지불할 송금 수수료입니다.</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>
</message>
@@ -2239,14 +2890,22 @@
<translation>Tor 서비스를 이용하여 피어에게 연결하기 위해 분리된 SOCKS5 프록시를 사용 (기본값: %s)</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. 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가 포함되어 있습니다. 이 옵션은 여러번 지정할 수 있습니다.</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>경고: 알려지지 않은 버전의 블록이 채굴되었습니다. 알려지지 않은 규칙이 적용되었을 가능성이 있습니다.</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>경고 : 지갑파일이 손상되어 데이터가 복구되었습니다. 원래의 %s 파일은 %s 후에 %s 이름으로 저장됩니다. 잔액과 거래 내역이 정확하지 않다면 백업 파일로 부터 복원해야 합니다. </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>설정된 IP주소 (보기 1.2.3.4) 혹은 CIDR로 작성된 네트워크 (보기 1.2.3.0/24)로 화이트리스트에 포함된 피어에 접속합니다. 이 설정은 복수로 지정 할 수 있습니다.</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 lookup을 통해 항상 피어주소에 대한 쿼리 보내기 (기본값: %u)</translation>
</message>
@@ -2323,6 +2982,10 @@
<translation>트랜잭션을 보낼 때 검증되지 않은 잔돈 쓰기 (기본값: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>네트워크 스레드 시작중...</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>이상행동 네트워크 참여자의 연결을 차단시키기 위한 한계치 (기본값: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ku_IQ.ts b/src/qt/locale/bitcoin_ku_IQ.ts
index da5e41a358..a0d8510413 100644
--- a/src/qt/locale/bitcoin_ku_IQ.ts
+++ b/src/qt/locale/bitcoin_ku_IQ.ts
@@ -25,7 +25,14 @@
<source>&amp;Delete</source>
<translation>&amp;سڕینەوە</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Address</source>
+ <translation>ناوونیشان</translation>
+ </message>
+ </context>
<context>
<name>AskPassphraseDialog</name>
</context>
@@ -70,10 +77,6 @@
<translation>کۆ:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>لەپێشی:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>تێچوون:</translation>
</message>
@@ -86,10 +89,14 @@
<translation>رێکەت</translation>
</message>
<message>
- <source>Priority</source>
- <translation>لەپێشی</translation>
+ <source>yes</source>
+ <translation>بەڵێ</translation>
</message>
-</context>
+ <message>
+ <source>no</source>
+ <translation>نەخێر</translation>
+ </message>
+ </context>
<context>
<name>EditAddressDialog</name>
</context>
@@ -119,6 +126,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -136,6 +146,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -146,20 +159,42 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>&amp;Information</source>
<translation>&amp;زانیاری</translation>
</message>
<message>
+ <source>General</source>
+ <translation>گشتی</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>تۆڕ</translation>
+ </message>
+ <message>
<source>Name</source>
<translation>ناو</translation>
</message>
<message>
+ <source>Sent</source>
+ <translation>نێدرا</translation>
+ </message>
+ <message>
<source>Version</source>
<translation>وەشان</translation>
</message>
<message>
+ <source>Services</source>
+ <translation>خزمەتگوزاریەکان</translation>
+ </message>
+ <message>
<source>&amp;Open</source>
<translation>&amp;کردنەوە</translation>
</message>
@@ -172,6 +207,34 @@
<translation>گشتییەکان</translation>
</message>
<message>
+ <source>In:</source>
+ <translation>لە ناو</translation>
+ </message>
+ <message>
+ <source>Out:</source>
+ <translation>لەدەرەوە</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>never</source>
+ <translation>هەرگیز</translation>
+ </message>
+ <message>
<source>Yes</source>
<translation>بەڵێ</translation>
</message>
@@ -202,9 +265,24 @@
<source>Remove</source>
<translation>سڕینەوە</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>ناوونیشان</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>سەرجەم</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>رێکەت</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -213,10 +291,6 @@
<translation>کۆ:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>لەپێشی:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>تێچوون:</translation>
</message>
@@ -233,6 +307,13 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>بەڵێ</translation>
+ </message>
+</context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -245,12 +326,54 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation>رێکەت</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>سەرجەم</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>رێکەت</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Date</source>
+ <translation>رێکەت</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>ناوونیشان</translation>
+ </message>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;هەناردن</translation>
+ </message>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_ky.ts b/src/qt/locale/bitcoin_ky.ts
index 14cb9c2020..da364c3bbc 100644
--- a/src/qt/locale/bitcoin_ky.ts
+++ b/src/qt/locale/bitcoin_ky.ts
@@ -9,6 +9,17 @@
<source>&amp;Delete</source>
<translation>Ө&amp;чүрүү</translation>
</message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Address</source>
+ <translation>Дарек</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(аты жок)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -65,6 +76,10 @@
<source>Date</source>
<translation>Дата</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation>(аты жок)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -72,7 +87,7 @@
<source>&amp;Address</source>
<translation>&amp;Дарек</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -91,6 +106,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -136,12 +154,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>&amp;Information</source>
@@ -181,6 +208,29 @@
</context>
<context>
<name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>Дарек</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Билдирүү</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Дата</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Билдирүү</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(аты жок)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -192,6 +242,10 @@
<source>S&amp;end</source>
<translation>&amp;Жөнөтүү</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation>(аты жок)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -205,6 +259,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -225,12 +282,58 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/тармакта эмес</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Дата</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Билдирүү</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Дата</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(аты жок)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Date</source>
+ <translation>Дата</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Дарек</translation>
+ </message>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Information</source>
diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts
index dc532fe011..d84dd7e4e2 100644
--- a/src/qt/locale/bitcoin_la.ts
+++ b/src/qt/locale/bitcoin_la.ts
@@ -25,7 +25,10 @@
<source>&amp;Delete</source>
<translation>&amp;Dele</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -44,7 +47,7 @@
<source>Repeat new passphrase</source>
<translation>Itera novam tesseram</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -191,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>
@@ -242,7 +241,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Cassidile &lt;b&gt;cifratum&lt;/b&gt; est et iam nunc &lt;b&gt;seratum&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -276,7 +275,7 @@
<source>&amp;Address</source>
<translation>&amp;Inscriptio</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -307,6 +306,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Schema</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Hora postremi frusti</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -428,6 +438,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -442,6 +455,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>N/A</source>
@@ -531,6 +550,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -572,7 +594,7 @@
<source>S&amp;end</source>
<translation>&amp;Mitte</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -609,6 +631,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -677,7 +702,7 @@
<source>Reset all verify message fields</source>
<translation>Reconstitue omnes campos verificandi nuntii</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -689,16 +714,34 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Haec tabula monstrat descriptionem verbosam transactionis</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -725,10 +768,6 @@
<translation>Operare infere sicut daemon et mandata accipe</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Accipe conexiones externas (praedefinitum: 1 nisi -proxy neque -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Nucleus</translation>
</message>
@@ -741,18 +780,10 @@
<translation>Facere mandatum quotiescumque cassidilis transactio mutet (%s in mandato sbstituitur ab TxID)</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>Hoc est prae-dimittum experimentala aedes - utere eo periculo tuo proprio - nolite utere fodendo vel applicationibus mercatoriis</translation>
- </message>
- <message>
<source>Block creation options:</source>
<translation>Optiones creandi frustorum:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Conecte sole ad nodos specificatos (vel nodum specificatum)</translation>
- </message>
- <message>
<source>Corrupted block database detected</source>
<translation>Corruptum databasum frustorum invenitur</translation>
</message>
@@ -817,10 +848,6 @@
<translation>Magnitudo transactionis nimis parva</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Necesse est magnitudines transactionum positivas esse.</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>Transactio nimis magna</translation>
</message>
diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts
index 1f6cda1f52..67fee9ae42 100644
--- a/src/qt/locale/bitcoin_lt.ts
+++ b/src/qt/locale/bitcoin_lt.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Trinti</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Pakartokite naują slaptafrazę</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -258,7 +261,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Piniginė &lt;b&gt;užšifruota&lt;/b&gt; ir šiuo metu &lt;b&gt;užrakinta&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -278,10 +281,6 @@
<translation>Suma:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Pirmumas:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Mokestis:</translation>
</message>
@@ -321,11 +320,7 @@
<source>Confirmed</source>
<translation>Patvirtintas</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Pirmumas</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -340,7 +335,7 @@
<source>&amp;Address</source>
<translation>&amp;Adresas</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -379,6 +374,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Paskutinio bloko laikas</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -540,6 +546,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -562,6 +571,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>N/A</source>
@@ -703,6 +718,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -725,10 +743,6 @@
<translation>Suma:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Pirmumas:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Mokestis:</translation>
</message>
@@ -768,7 +782,7 @@
<source>S&amp;end</source>
<translation>&amp;Siųsti</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -805,6 +819,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -869,16 +886,34 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Šis langas sandorio detalų aprašymą</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -905,10 +940,6 @@
<translation>Bitcoin branduolys</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Prisijungti tik prie nurodyto mazgo</translation>
- </message>
- <message>
<source>Error opening block database</source>
<translation>Klaida atveriant blokų duombazę</translation>
</message>
diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts
index 38333531e4..2953da443a 100644
--- a/src/qt/locale/bitcoin_lv_LV.ts
+++ b/src/qt/locale/bitcoin_lv_LV.ts
@@ -37,7 +37,10 @@
<source>&amp;Delete</source>
<translation>&amp;Dzēst</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -56,7 +59,7 @@
<source>Repeat new passphrase</source>
<translation>Jaunā parole vēlreiz</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -227,14 +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 and %2</source>
- <translation>%1 un %2</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 aizmugurē</translation>
</message>
@@ -278,7 +273,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Maciņš ir &lt;b&gt;šifrēts&lt;/b&gt; un pašlaik &lt;b&gt;slēgts&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -294,10 +289,6 @@
<translation>Daudzums:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritāte:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Maksa:</translation>
</message>
@@ -337,11 +328,7 @@
<source>Confirmed</source>
<translation>Apstiprināts</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioritāte</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -356,7 +343,7 @@
<source>&amp;Address</source>
<translation>&amp;Adrese</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -419,6 +406,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Pēdējā bloka laiks</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -436,7 +434,7 @@
<source>Select payment request file</source>
<translation>Izvēlies maksājuma pieprasījuma datni</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -628,6 +626,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -648,6 +649,16 @@
<source>N/A</source>
<translation>N/A</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 un %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -810,7 +821,7 @@
<source>Remove</source>
<translation>Noņemt</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -829,7 +840,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Saglabāt Attēlu...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -865,10 +879,6 @@
<translation>Daudzums:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritāte:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Maksa:</translation>
</message>
@@ -916,7 +926,7 @@
<source>S&amp;end</source>
<translation>&amp;Sūtīt</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -967,7 +977,10 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1041,7 +1054,7 @@
<source>Reset all verify message fields</source>
<translation>Atiestatīt visus laukus</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1057,16 +1070,34 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Šis panelis parāda transakcijas detaļas</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1105,10 +1136,6 @@
<translation>Bloka izveidošanas iestatījumi:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Savienoties tikai ar norādītajām nodēm.</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Savienojuma iestatījumi:</translation>
</message>
@@ -1161,10 +1188,6 @@
<translation>Transakcijas summa ir pārāk maza</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Transakcijas summai ir jābūt pozitīvai</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>Transakcija ir pārāk liela</translation>
</message>
diff --git a/src/qt/locale/bitcoin_mk_MK.ts b/src/qt/locale/bitcoin_mk_MK.ts
index b696111a53..e11e415ec5 100644
--- a/src/qt/locale/bitcoin_mk_MK.ts
+++ b/src/qt/locale/bitcoin_mk_MK.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Избриши</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -56,7 +59,7 @@
<source>Repeat new passphrase</source>
<translation>Повторете ја новата тајна фраза</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -178,26 +181,6 @@
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Обработен %n блок од историјата на трансакции.</numerusform><numerusform>Обработени %n блокови од историјата на трансакции.</numerusform></translation>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n час</numerusform><numerusform>%n часови</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n ден</numerusform><numerusform>%n денови</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><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></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 позади</translation>
@@ -256,10 +239,6 @@
<translation>Сума:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Приоритет:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Провизија:</translation>
</message>
@@ -283,11 +262,7 @@
<source>Date</source>
<translation>Дата</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Приоритет</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -302,7 +277,7 @@
<source>&amp;Address</source>
<translation>&amp;Адреса</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -329,6 +304,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -382,6 +360,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -410,7 +391,17 @@
<source>%1 ms</source>
<translation>%1 мс</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 и %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -495,7 +486,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Сними Слика...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -507,10 +501,6 @@
<translation>Сума:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Приоритет:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Провизија:</translation>
</message>
@@ -543,6 +533,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -555,12 +548,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_mn.ts b/src/qt/locale/bitcoin_mn.ts
index d9ef0d127b..6e13d21288 100644
--- a/src/qt/locale/bitcoin_mn.ts
+++ b/src/qt/locale/bitcoin_mn.ts
@@ -37,7 +37,10 @@
<source>&amp;Delete</source>
<translation>&amp;Устгах</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -52,7 +55,7 @@
<source>Repeat new passphrase</source>
<translation>Шинэ нууц үгийг давтана уу</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -174,7 +177,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -212,7 +215,7 @@
<source>&amp;Address</source>
<translation>&amp;Хаяг</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -235,6 +238,13 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Last block time</source>
+ <translation>Сүүлийн блокийн хугацаа</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -276,6 +286,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -290,6 +303,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>N/A</source>
@@ -370,7 +389,7 @@
<source>Remove</source>
<translation>Устгах</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -379,6 +398,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -424,7 +446,7 @@
<source>S&amp;end</source>
<translation>Яв&amp;уул</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -461,6 +483,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
<message>
<source>Do not shut down the computer until this window disappears.</source>
@@ -493,16 +518,34 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Гүйлгээний дэлгэрэнгүйг энэ бичил цонх харуулж байна</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_ms_MY.ts b/src/qt/locale/bitcoin_ms_MY.ts
index acfb38e418..0108332dd7 100644
--- a/src/qt/locale/bitcoin_ms_MY.ts
+++ b/src/qt/locale/bitcoin_ms_MY.ts
@@ -34,7 +34,10 @@ Alihkan fail data ke dalam tab semasa</translation>
<source>&amp;Delete</source>
<translation>&amp;Padam</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
</context>
@@ -61,7 +64,7 @@ Alihkan fail data ke dalam tab semasa</translation>
<source>&amp;Address</source>
<translation>Alamat</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -72,6 +75,9 @@ Alihkan fail data ke dalam tab semasa</translation>
<name>Intro</name>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -81,12 +87,21 @@ Alihkan fail data ke dalam tab semasa</translation>
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -100,6 +115,9 @@ Alihkan fail data ke dalam tab semasa</translation>
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Balance:</source>
@@ -110,6 +128,9 @@ Alihkan fail data ke dalam tab semasa</translation>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -122,12 +143,35 @@ Alihkan fail data ke dalam tab semasa</translation>
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>
+Alihkan fail data ke dalam tab semasa</translation>
+ </message>
+ </context>
+<context>
<name>bitcoin-core</name>
</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts
index 4538fd6e1e..183cbac80a 100644
--- a/src/qt/locale/bitcoin_nb.ts
+++ b/src/qt/locale/bitcoin_nb.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Slett</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Gjenta ny adgangsfrase</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -115,6 +118,10 @@
<translation> &amp;Om %1</translation>
</message>
<message>
+ <source>Show information about %1</source>
+ <translation>Vis informasjon om %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>Om &amp;Qt</translation>
</message>
@@ -127,6 +134,10 @@
<translation>&amp;Innstillinger...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Endre innstilinger for %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Krypter Lommebok...</translation>
</message>
@@ -254,34 +265,10 @@
<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>
</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>
<message>
<source>%1 behind</source>
<translation>%1 bak</translation>
@@ -311,6 +298,10 @@
<translation>Oppdatert</translation>
</message>
<message>
+ <source>%1 client</source>
+ <translation>%1 klient</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Laster ned...</translation>
</message>
@@ -360,7 +351,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -380,10 +371,6 @@
<translation>Beløp:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritet:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Avgift:</translation>
</message>
@@ -435,11 +422,7 @@
<source>Confirmed</source>
<translation>Bekreftet</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioritet</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -462,7 +445,7 @@
<source>&amp;Address</source>
<translation>&amp;Adresse</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -497,6 +480,10 @@
<translation> (%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>Om %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Kommandolinjevalg</translation>
</message>
@@ -540,6 +527,10 @@
<translation>Velkommen</translation>
</message>
<message>
+ <source>Welcome to %1.</source>
+ <translation>Velkommen til %1.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Bruk standard datamappe</translation>
</message>
@@ -565,6 +556,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Skjema</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Tidspunkt for siste blokk</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Skjul</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -582,7 +588,7 @@
<source>Select payment request file</source>
<translation>Velg fil for betalingsetterspørring</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -730,6 +736,10 @@
<translation>&amp;Vindu</translation>
</message>
<message>
+ <source>Hide tray icon</source>
+ <translation>Skjul søppel ikon</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation>Vis kun ikon i systemkurv etter minimering av vinduet.</translation>
</message>
@@ -874,6 +884,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -883,11 +896,7 @@
<source>Node/Service</source>
<translation>Node/Tjeneste</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Ping-tid</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -926,7 +935,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 og %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -1038,6 +1057,14 @@
<translation>Brukeragent</translation>
</message>
<message>
+ <source>Decrease font size</source>
+ <translation>Forminsk font størrelsen</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation>Forstørr font størrelse</translation>
+ </message>
+ <message>
<source>Services</source>
<translation>Tjenester</translation>
</message>
@@ -1114,14 +1141,6 @@
<translation>Tøm konsoll</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Koble fra node</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Steng node ute for</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;time</translation>
</message>
@@ -1138,10 +1157,6 @@
<translation>1 &amp;år</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>Fjern &amp;Utestengning av Node</translation>
- </message>
- <message>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
<translation>Bruk opp og ned pil for å navigere historikken, og &lt;b&gt;Ctrl-L&lt;/b&gt; for å tømme skjermen.</translation>
</message>
@@ -1268,7 +1283,7 @@
<source>Remove</source>
<translation>Fjern</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1287,7 +1302,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Lagre Bilde...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1323,10 +1341,6 @@
<translation>Beløp:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritet:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Gebyr:</translation>
</message>
@@ -1395,10 +1409,6 @@
<translation>(Smartgebyr ikke innført ennå. Dette tar vanligvis noen blokker...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Bekreftelsestid:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1438,7 +1448,7 @@
<source>S&amp;end</source>
<translation>S&amp;end</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1517,7 +1527,10 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1611,7 +1624,7 @@
<source>Reset all verify message fields</source>
<translation>Tilbakestill alle felter for meldingsverifikasjon</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1627,12 +1640,21 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Her vises en detaljert beskrivelse av transaksjonen</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1641,6 +1663,15 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1675,10 +1706,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>
@@ -1703,10 +1730,6 @@
<translation>Kunne ikke starte HTTP server. Se debug logg for detaljer.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Ta imot tilkoblinger fra utsiden (standardverdi: 1 hvis uten -proxy eller -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1719,10 +1742,6 @@
<translation>Slett alle transaksjoner i lommeboken og gjenopprett kun de delene av blokkjeden gjennom -rescan ved oppstart</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuert under MIT programvarelisensen, se medfølgende fil COPYING eller &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Kjør kommando når en lommeboktransaksjon endres (%s i kommando er erstattet med TxID)</translation>
</message>
@@ -1735,26 +1754,10 @@
<translation>Blokkdatabasen inneholder en blokk som ser ut til å være fra fremtiden. Dette kan være fordi dato og tid på din datamaskin er satt feil. Gjenopprett kun blokkdatabasen når du er sikker på at dato og tid er satt riktig.</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>Dette er en forhåndssluppet testversjon - bruk på egen risiko - ikke for bruk til blokkutvinning eller bedriftsapplikasjoner</translation>
- </message>
- <message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<translation>Bruk UPnP for lytteport (standardverdi: 1 ved lytting og uten -proxy)</translation>
</message>
<message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Advarsel: Nettverket ser ikke ut til å være enig! Noen minere ser ut til å ha problemer.</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>Advarsel: Vi ser ikke ut til å være enige med våre noder! Du må oppgradere, eller andre noder må oppgradere.</translation>
- </message>
- <message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Hvitelist noder som kobler til fra den oppgitte nettmasken eller IP-adressen. Kan oppgis flere ganger.</translation>
- </message>
- <message>
<source>-maxmempool must be at least %d MB</source>
<translation>-maxmempool må være minst %d MB</translation>
</message>
@@ -1767,10 +1770,6 @@
<translation>Valg for opprettelse av blokker:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Koble kun til angitt(e) node(r)</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Innstillinger for tilkobling:</translation>
</message>
@@ -1815,6 +1814,10 @@
<translation>Feil under oppstart av lommeboken sitt databasemiljø %s!</translation>
</message>
<message>
+ <source>Error loading %s</source>
+ <translation>Feil ved lasting av %s</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>Feil ved lasting av blokkdatabase</translation>
</message>
@@ -1855,6 +1858,14 @@
<translation>Bare koble til noder i nettverket &lt;net&gt; (IPv4, IPv6 eller onion)</translation>
</message>
<message>
+ <source>Print this help message and exit</source>
+ <translation>Skriv ut denne hjelpemeldingen og avslutt</translation>
+ </message>
+ <message>
+ <source>Print version and exit</source>
+ <translation>Skriv ut denne versjonen og avslutt</translation>
+ </message>
+ <message>
<source>Prune cannot be configured with a negative value.</source>
<translation>Beskjæringsmodus kan ikke konfigureres med en negativ verdi.</translation>
</message>
@@ -1875,6 +1886,10 @@
<translation>Angi lommebokfil (inne i datamappe)</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation>Kildekoden er tilgjengelig fra %s.</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Ustøttet argument -benchmark ble ignorert, bruk -debug=bench.</translation>
</message>
@@ -1955,10 +1970,6 @@
<translation>Maksimal størrelse på data i databærende transaksjoner vi videresender og ufører graving på (standardverdi: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Søk etter nodeadresser via DNS-oppslag, hvis vi har få adresser å koble til (standard: 1 med mindre -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Bruk tilfeldig identitet for hver proxytilkobling. Dette muliggjør TOR stream isolasjon (standardverdi: %u)</translation>
</message>
@@ -1971,10 +1982,6 @@
<translation>Transaksjonsbeløpet er for lite til å sendes etter at gebyret er fratrukket</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Dette produktet inneholder programvare utviklet av OpenSSL Project for bruk i OpenSSL Toolkit &lt;https://www.openssl.org/&gt; og kryptografisk programvare skrevet av Eric Young og UPnP-programvare skrevet av Thomas Bernard.</translation>
- </message>
- <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>Hvitlistede noder kan ikke DoS-blokkeres, og deres transaksjoner videresendes alltid, selv om de allerede er i minnelageret. Nyttig f.eks. for en gateway.</translation>
</message>
@@ -2083,10 +2090,6 @@
<translation>Transaksjonen er for liten</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Transaksjonsbeløpet må være positivt</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transaksjon for stor for gebyrpolitikken</translation>
</message>
@@ -2147,10 +2150,6 @@
<translation>-maxtxfee er satt veldig høyt! Så stort gebyr kan bli betalt ved en enkelt transaksjon.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee er satt veldig høyt! Dette er transaksjonsgebyret du betaler når du sender transaksjoner.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Ikke hold transaksjoner i minnet lenger enn &lt;n&gt; timer (standard: %u)</translation>
</message>
@@ -2195,10 +2194,6 @@
<translation>Bruk separate SOCKS5 proxyer for å nå noder via Tor skjulte tjenester (standardverdi: %s)</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. This option can be specified multiple times</source>
- <translation>Brukernavn og hashet passord for JSON-RPC tilkoblinger. Feltet &lt;userpw&gt; kommer i formatet: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Et Python-skript er inkludert i share/rpcuser. Dette alternativet kan angis flere ganger</translation>
- </message>
- <message>
<source>(default: %s)</source>
<translation>(standardverdi: %s)</translation>
</message>
@@ -2259,10 +2254,6 @@
<translation>Angi størrelse på nøkkel-lager til &lt;n&gt; (standardverdi: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Sett minimum blokkstørrelse i bytes (standardverdi: %u)</translation>
- </message>
- <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>Sett antall tråder til betjening av RPC-kall (standardverdi: %d)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ne.ts b/src/qt/locale/bitcoin_ne.ts
new file mode 100644
index 0000000000..f7fb0e5a6e
--- /dev/null
+++ b/src/qt/locale/bitcoin_ne.ts
@@ -0,0 +1,555 @@
+<TS language="ne" version="2.1">
+<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>&amp;amp;नयाँ</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation>भर्खरै चयन गरेको ठेगाना प्रणाली क्लिपबोर्डमा कपी गर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation>&amp;amp;कपी गर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation>बन्द गर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>भर्खरै चयन गरेको ठेगाना सूचीबाट मेटाउनुहोस्</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>वर्तमान ट्याबको डाटालाई फाइलमा निर्यात गर्नुहोस् </translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;amp;निर्यात गर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation>&amp;amp;मेटाउनुहोस्</translation>
+ </message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </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>
+ </context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/नेटमास्क</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>प्रतिबन्धित समय</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>Sign &amp;message...</source>
+ <translation>सन्देशमा &amp;amp;हस्ताक्षर गर्नुहोस्...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network...</source>
+ <translation>नेटवर्कमा समिकरण हुँदै...</translation>
+ </message>
+ <message>
+ <source>&amp;Overview</source>
+ <translation>शारांश</translation>
+ </message>
+ <message>
+ <source>Node</source>
+ <translation>नोड</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation>वालेटको साधारण शारांश देखाउनुहोस्</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation>&amp;amp;कारोबार</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation>कारोबारको इतिहास हेर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation>बाहिर निस्कनुहोस्</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>एप्लिकेसन बन्द गर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation>&amp;amp;बारेमा %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>%1 को बारेमा सूचना देखाउनुहोस्</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation>&amp;amp;Qt</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>Qt को बारेमा सूचना देखाउनुहोस्</translation>
+ </message>
+ <message>
+ <source>&amp;Options...</source>
+ <translation>&amp;amp;विकल्प...</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation>%1 का लागि कन्फिगुरेसनको विकल्प परिमार्जन गर्नुहोस</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet...</source>
+ <translation>&amp;amp;वालेटलाई इन्क्रिप्ट गर्नुहोस्...</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet...</source>
+ <translation>&amp;amp;वालेटलाई ब्याकअप गर्नुहोस्...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>&amp;amp;पासफ्रेज परिवर्तन गर्नुहोस्...</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;amp;पठाउने ठेगानाहरू...</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>&amp;amp;प्राप्त गर्ने ठेगानाहरू...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>URI &amp;amp;खोल्नुहोस्...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk...</source>
+ <translation>डिस्कमा ब्लकलाई पुनः सूचीकरण गरिँदै...</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation>बिटकोइन ठेगानामा सिक्का पठाउनुहोस्</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation>वालेटलाई अर्को ठेगानामा ब्याकअप गर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation>वालेट इन्क्रिप्सनमा प्रयोग हुने इन्क्रिप्सन पासफ्रेज परिवर्तन गर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>&amp;Debug window</source>
+ <translation>&amp;amp;डिबग विन्डो</translation>
+ </message>
+ <message>
+ <source>Open debugging and diagnostic console</source>
+ <translation>डिबगिङ र डायाग्नोस्टिक कन्सोल खोल्नुहोस्</translation>
+ </message>
+ </context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>Amount</source>
+ <translation>रकम</translation>
+ </message>
+ </context>
+<context>
+ <name>EditAddressDialog</name>
+ </context>
+<context>
+ <name>FreespaceChecker</name>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
+ </context>
+<context>
+ <name>Intro</name>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
+ <name>OpenURIDialog</name>
+ </context>
+<context>
+ <name>OptionsDialog</name>
+ </context>
+<context>
+ <name>OverviewPage</name>
+ <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>देखाइएको सूचना पूरानो हुन सक्छ । कनेक्सन स्थापित भएपछि, तपाईंको वालेट बिटकोइन नेटवर्कमा स्वचालित रूपमा समिकरण हुन्छ , तर यो प्रक्रिया अहिले सम्म पूरा भएको छैन ।</translation>
+ </message>
+ <message>
+ <source>Watch-only:</source>
+ <translation>हेर्ने-मात्र:</translation>
+ </message>
+ <message>
+ <source>Available:</source>
+ <translation>उपलब्ध:</translation>
+ </message>
+ <message>
+ <source>Your current spendable balance</source>
+ <translation>तपाईंको खर्च गर्न मिल्ने ब्यालेन्स</translation>
+ </message>
+ <message>
+ <source>Pending:</source>
+ <translation>विचाराधिन:</translation>
+ </message>
+ <message>
+ <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
+ <translation>अझै पुष्टि हुन बाँकी र खर्च गर्न मिल्ने ब्यालेन्समा गणना गर्न नमिल्ने जम्मा कारोबार</translation>
+ </message>
+ <message>
+ <source>Immature:</source>
+ <translation>अपरिपक्व:</translation>
+ </message>
+ <message>
+ <source>Mined balance that has not yet matured</source>
+ <translation>अझै परिपक्व नभएको खनन गरिएको ब्यालेन्स</translation>
+ </message>
+ <message>
+ <source>Balances</source>
+ <translation>ब्यालेन्स</translation>
+ </message>
+ <message>
+ <source>Mined balance in watch-only addresses that has not yet matured</source>
+ <translation>अहिलेसम्म परिपक्व नभएको खनन गरिएको, हेर्ने-मात्र ठेगानामा रहेको ब्यालेन्स</translation>
+ </message>
+ <message>
+ <source>Current total balance in watch-only addresses</source>
+ <translation>हेर्ने-मात्र ठेगानामा रहेको हालको जम्मा ब्यालेन्स</translation>
+ </message>
+</context>
+<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ <message>
+ <source>User Agent</source>
+ <translation>प्रयोगकर्ता एजेन्ट</translation>
+ </message>
+ <message>
+ <source>Node/Service</source>
+ <translation>नोड/सेव</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Amount</source>
+ <translation>रकम</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>User Agent</source>
+ <translation>प्रयोगकर्ता एजेन्ट</translation>
+ </message>
+ <message>
+ <source>Ping Time</source>
+ <translation>पिङ समय</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ </context>
+<context>
+ <name>SendCoinsEntry</name>
+ <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>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>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
+ <name>ShutdownWindow</name>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ <message>
+ <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source>
+ <translation>आफ्नो ठेगानामा पठाइएको बिटकोइन प्राप्त गर्न सकिन्छ भनेर प्रमाणित गर्न तपाईंले ती ठेगानाले सन्देश/सम्झौताहरूमा हस्ताक्षर गर्न सक्नुहुन्छ । फिसिङ आक्रमणले तपाईंलाई छक्याएर अरूका लागि तपाईंको परिचयमा हस्ताक्षर गराउने प्रयास गर्न सक्ने भएकाले अस्पष्ट वा जथाभावीमा हस्ताक्षर गर्दा ध्यान दिनुहोस् । आफू सहमत भएको पूर्ण विस्तृत-कथनमा मात्र हस्ताक्षर गर्नुहोस् ।</translation>
+ </message>
+ </context>
+<context>
+ <name>SplashScreen</name>
+ </context>
+<context>
+ <name>TrafficGraphWidget</name>
+ </context>
+<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
+ <name>TransactionDescDialog</name>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <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>
+ <message>
+ <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
+ <translation>प्रि-फर्क अवस्थामा डाटाबेस रिवाइन्ड गर्न सकिएन । तपाईंले फेरि ब्लकचेन डाउनलोड गर्नु पर्ने हुन्छ</translation>
+ </message>
+ <message>
+ <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
+ <translation>UPnP प्रयोग गरेर सुन्ने पोर्टलाई म्याप गर्नुहोस् (सुन्दा र -प्रोक्सी नहुँदा डिफल्ट: 1)</translation>
+ </message>
+ <message>
+ <source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
+ <translation>तपाईंले -चेनस्टेट-पुनः सूचकांकबाट -txindex परिवर्तन प्रयोग गरेर डाटाबेस पुनर्निर्माण गर्नु आवश्यक छ</translation>
+ </message>
+ <message>
+ <source>%s corrupt, salvage failed</source>
+ <translation>%s मा क्षति, बचाव विफल भयो</translation>
+ </message>
+ <message>
+ <source>-maxmempool must be at least %d MB</source>
+ <translation>-maxmempool कम्तिमा %d MB को हुनुपर्छ ।</translation>
+ </message>
+ <message>
+ <source>&lt;category&gt; can be:</source>
+ <translation>&amp;lt;वर्ग&amp;gt; निम्न आकारको हुनसक्छ:</translation>
+ </message>
+ <message>
+ <source>Append comment to the user agent string</source>
+ <translation>प्रयोगकर्ता एजेन्ट स्ट्रिङमा टिप्पणी जोड्नुहोस्</translation>
+ </message>
+ <message>
+ <source>Attempt to recover private keys from a corrupt wallet on startup</source>
+ <translation>स्टार्टअपमा क्षति पूगेको वालेटबाट निजी की प्राप्त गर्न प्रयास गर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>Block creation options:</source>
+ <translation>ब्लक सिर्जनाको बिकल्प:</translation>
+ </message>
+ <message>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>-%s ठेगाना: &amp;apos;%s&amp;apos; निश्चय गर्न सकिँदैन</translation>
+ </message>
+ <message>
+ <source>Change index out of range</source>
+ <translation>सूचकांक परिवर्तन सीमा भन्दा बाहर</translation>
+ </message>
+ <message>
+ <source>Connection options:</source>
+ <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>
+ <message>
+ <source>Debugging/Testing options:</source>
+ <translation>डिबगिङ/परीक्षणका विकल्पहरू:</translation>
+ </message>
+ <message>
+ <source>Do not load the wallet and disable wallet RPC calls</source>
+ <translation>वालेट लोड नगर्नुहोस् र वालेट RPC कलहरू अक्षम गर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>Do you want to rebuild the block database now?</source>
+ <translation>तपाईं अहिले ब्लक डेटाबेस पुनर्निर्माण गर्न चाहनुहुन्छ ?</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation>यो कम्प्युटरको %s मा बाँध्न सकिएन । %s सम्भवित रूपमा पहिलैबाट चलिरहेको छ ।</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
+ <translation>असमर्थित तर्क -बेन्चमार्कलाई बेवास्ता गरियो, -डिबग=बेन्च प्रयोग गर्नुहोस् ।</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -debugnet ignored, use -debug=net.</source>
+ <translation>असमर्थित तर्क -डिबगनेटलाई बेवास्ता गरियो, -डिबग=नेट प्रयोग गर्नुहोस् । </translation>
+ </message>
+ <message>
+ <source>Unsupported argument -tor found, use -onion.</source>
+ <translation>असमर्थित तर्क -टोर फेला पर्यो, -ओनियन प्रयोग गर्नुहोस् । </translation>
+ </message>
+ <message>
+ <source>Use UPnP to map the listening port (default: %u)</source>
+ <translation>UPnP प्रयोग गरेर सुन्ने पोर्ट म्याप गर्नुहोस् (डिफल्ट: %u) </translation>
+ </message>
+ <message>
+ <source>Verifying blocks...</source>
+ <translation>ब्लक प्रमाणित गरिँदै...</translation>
+ </message>
+ <message>
+ <source>Verifying wallet...</source>
+ <translation>वालेट प्रमाणित गरिँदै...</translation>
+ </message>
+ <message>
+ <source>Wallet %s resides outside data directory %s</source>
+ <translation>वालेट %s डाटा निर्देशिका %s बाहिरमा बस्छ</translation>
+ </message>
+ <message>
+ <source>Wallet debugging/testing options:</source>
+ <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>
+ <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>निर्दिष्ट गरिएको स्रोतबाट आएको JSON-RPC कनेक्सनलाई अनुमति दिनुहोस् । एकल IP (e.g. 1.2.3.4), नेटवर्क/नेटमास्क (उदाहरण 1.2.3.4/255.255.255.0) वा नेटवर्क/CIDR (उदाहरण 1.2.3.4/24) &amp;lt;ip&amp;gt; का लागि मान्य छन् । यो विकल्पलाई धेरै पटक निर्दिष्ट गर्न सकिन्छ</translation>
+ </message>
+ <message>
+ <source>Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6</source>
+ <translation>दिइएको ठेगानामा बाँध्नुहोस् र यसमा कनेक्ट गर्ने सहकर्मीलाई श्वेतसूचीमा राख्नुहोस् । IPv6 लागि [होस्ट]:पोर्ट संकेतन प्रयोग गर्नुहोस्</translation>
+ </message>
+ <message>
+ <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>JSON-RPC कनेक्सन सुन्नको लागि दिइएको ठेगानामा बाँध्नुहोस् । IPv6 लागि [होस्ट]:पोर्ट संकेतन प्रयोग गर्नुहोस् । यो विकल्पलाई धेरै पटक निर्दिष्ट गर्न सकिन्छ (डिफल्ट: सबै इन्टरफेसमा बाँध्नुहोस्)</translation>
+ </message>
+ <message>
+ <source>Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)</source>
+ <translation>umask 077 को सट्टामा प्रणालीको डिफल्ट अनुमतिको साथमा नयाँ फाइलहरू सिर्जना गर्नुहोस् । (असक्षम गरिएको वालेट कार्यक्षमतामा मात्र प्रभावकारी हुने)</translation>
+ </message>
+ <message>
+ <source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source>
+ <translation>आफ्नै IP ठेगाना पत्ता लगाउनुहोस् (सुन्दा र -बाहिरीआइपी वा -प्रोक्सी नहुँदा डिफल्ट: 1 )</translation>
+ </message>
+ <message>
+ <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
+ <translation>त्रुटि: आगमन कनेक्सनमा सुन्ने कार्य असफल भयो (सुन्ने कार्यले त्रुटि %s फर्कायो)</translation>
+ </message>
+ <message>
+ <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>सान्दर्भिक चेतावनी प्राप्त गर्दा आदेश कार्यान्वयन गर्नुहोस् नभए धेरै लामो फोर्क देखा पर्न सक्छ । (cmd को %s लाई सन्देशले प्रतिस्थापन गर्छ)</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>रिले, खनन वा कारोबारको सिर्जनाको लागि यो भन्दा कम शुल्क (%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>
+ <translation>paytxfee सेट गरिएको छैन भने, औसतमा n ब्लक भित्र कारोबार पुष्टिकरण सुरु होस् भन्नका लागि पर्याप्त शुल्क समावेश गर्नुहोस् (डिफल्ट: %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=&amp;lt;रकम&amp;gt;: का लागि अमान्य रकम &amp;apos;%s&amp;apos; (कारोबारलाई अड्कन नदिन अनिवार्य रूपमा कम्तिमा %s को न्यूनतम रिले शुल्क हुनु पर्छ)</translation>
+ </message>
+ <message>
+ <source>Maximum size of data in data carrier transactions we relay and mine (default: %u)</source>
+ <translation>हामीले रिले र खनन गर्ने डाटा वाहक कारोबारको डाटाको अधिकतम आकार (डिफल्ट: %u)</translation>
+ </message>
+ <message>
+ <source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
+ <translation>हरेक प्रोक्सी कनेक्सनका लागि क्रेडिन्सियल अनियमित बनाउनुहोस् । यसले टोर स्ट्रिमको अलगावलाई सक्षम पार्छ (डिफल्ट: %u)</translation>
+ </message>
+ <message>
+ <source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
+ <translation>बाइटमा उच्च-प्राथमिकता/कम शुल्कको कारोबारको अधिकतम आकार सेट गर्नुहोस् (डिफल्ट: %d)</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <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 banned गर्न सकिँदैन र उनीहरूको कारोबार सधैं रिले हुन्छ, उदाहरण, गेटवेको लाग</translation>
+ </message>
+ <message>
+ <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
+ <translation>तपाईंले काटछाँट नगरेको मोडमा जान पुनः सूचकांक प्रयोग गरेर डाटाबेस पुनर्निर्माण गर्नु पर्ने हुन्छ । यसले सम्पूर्ण ब्लकचेनलाई फेरि डाउनलोड गर्नेछ</translation>
+ </message>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts
index 781c5a8fd6..2b625b5a07 100644
--- a/src/qt/locale/bitcoin_nl.ts
+++ b/src/qt/locale/bitcoin_nl.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Verwijder</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Kies het adres om munten naar te versturen</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Kies het adres om munten op te ontvangen</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>K&amp;iezen</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Verzendadressen</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Ontvangstadressen</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>Dit zijn uw Bitcoinadressen om betalingen mee te verzenden. Controleer altijd het bedrag en het ontvangstadres voordat u uw bitcoins verzendt.</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>Dit zijn uw Bitcoin-adressen waarmee u betalingen kunt ontvangen. We raden u aan om een nieuw ontvangstadres voor elke transactie te gebruiken.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopiëer Adres</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopieer &amp;Label</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Bewerk</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exporteer adreslijst</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kommagescheiden bestand (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Export mislukt</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Een fout is opgetreden tijdens het opslaan van deze adreslijst naar %1. Probeer het nogmaals.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen label)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>Herhaal nieuw wachtwoord</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>Voer een nieuw wachtwoord in voor uw portemonnee.&lt;br/&gt;Gebruik een wachtwoord van &lt;b&gt;tien of meer willekeurige karakters&lt;/b&gt;, of &lt;b&gt;acht of meer woorden&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Versleutel portemonnee</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Deze operatie vereist uw portemonneewachtwoord om de portemonnee te openen.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Open portemonnee</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Deze operatie vereist uw portemonneewachtwoord om de portemonnee te ontsleutelen</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Ontsleutel portemonnee</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Wijzig wachtwoord</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Voer het oude en nieuwe wachtwoord in voor uw portemonnee.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Bevestig versleuteling van de portemonnee</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>Waarschuwing: Als u uw portemonnee versleutelt en uw wachtwoord vergeet, zult u &lt;b&gt;AL UW BITCOINS VERLIEZEN&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Weet u zeker dat u uw portemonnee wilt versleutelen?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Portemonnee versleuteld</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 zal nu afsluiten om het versleutelingsproces te voltooien. Onthoud dat het versleutelen van uw portemonnee u niet volledig kan beschermen: Malware kan uw computer infecteren en uw bitcoins stelen.</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>BELANGRIJK: Elke eerder gemaakte backup van uw portemonneebestand dient u te vervangen door het nieuw gegenereerde, versleutelde portemonneebestand. Om veiligheidsredenen zullen eerdere backups van het niet-versleutelde portemonneebestand onbruikbaar worden zodra u uw nieuwe, versleutelde, portemonnee begint te gebruiken.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Portemonneeversleuteling mislukt</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Portemonneeversleuteling mislukt door een interne fout. Uw portemonnee is niet versleuteld.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>De opgegeven wachtwoorden komen niet overeen</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Portemonnee openen mislukt</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Het opgegeven wachtwoord voor de portemonnee-ontsleuteling is niet correct.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Portemonnee-ontsleuteling mislukt</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Portemonneewachtwoord is met succes gewijzigd.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Waarschuwing: De Caps-Lock-toets staat aan!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -270,34 +429,10 @@
<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>
</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>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n jaar</numerusform><numerusform>%n jaren</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 achter</translation>
@@ -384,7 +519,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -404,10 +539,6 @@
<translation>Bedrag:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioriteit:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Transactiekosten:</translation>
</message>
@@ -460,8 +591,84 @@
<translation>Bevestigd</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Prioriteit</translation>
+ <source>Copy address</source>
+ <translation>Kopieer adres</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopieer label</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopieer bedrag</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopieer transactie-ID</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Blokeer ongebruikte</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Deblokkeer ongebruikte</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopieer aantal</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopieer vergoeding</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopieer na vergoeding</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopieer bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopieër stof</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopieer wijziging</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 geblokkeerd)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>ja</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>nee</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Dit label wordt rood, als een ontvanger een bedrag van minder dan de huidige dust-drempel gekregen heeft.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Kan per input +/- %1 satoshi(s) variëren.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen label)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>wijzig van %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(wijzig)</translation>
</message>
</context>
<context>
@@ -486,6 +693,38 @@
<source>&amp;Address</source>
<translation>&amp;Adres</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nieuw ontvangstadres</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nieuw verzendadres</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Bewerk ontvangstadres</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Bewerk verzendadres</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Het opgegeven adres "%1" is een ongeldig Bitcoinadres.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Het opgegeven adres "%1" bestaat al in uw adresboek.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Kon de portemonnee niet openen.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Genereren nieuwe sleutel mislukt.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -609,6 +848,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Vorm</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Tijd laatste blok</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Verbergen</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -626,6 +880,10 @@
<source>Select payment request file</source>
<translation>Selecteer betalingsverzoek bestand</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Selecteer betalingsverzoekbestand om te openen</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -938,6 +1196,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Fout bij betalingsverzoek</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Kan bitcoin niet starten: click-to-pay handler</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>URI-behandeling</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>URL om betalingsverzoek te verkrijgen is ongeldig: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Ongeldig betalingsadres %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 niet verwerkt worden! Dit kan het gevolg zijn van een ongeldig Bitcoin adres of misvormde URI parameters.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Betalingsverzoek bestandsafhandeling</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>Betalingsverzoekbestand kan niet gelezen of verwerkt worden! Dit kan veroorzaakt worden door een ongeldig betalingsverzoekbestand.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Betalingsverzoek geweigerd</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Betalingsaanvraagnetwerk komt niet overeen met klantennetwerk.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Betalingsverzoek verlopen.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Betalingsaanvraag is niet geïnitialiseerd.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Niet-geverifieerde betalingsverzoeken naar aangepaste betalingsscripts worden niet ondersteund.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Ongeldig betalingsverzoek.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Het gevraagde betalingsbedrag van %1 is te weinig (beschouwd als stof).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Restitutie van %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>Betalingsverzoek %1 is te groot (%2 bytes, toegestaan ​​%3 bytes).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Fout bij communiceren met %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Betalingsverzoek kan niet worden verwerkt!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Ongeldige respons van server %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Fout bij netwerkverzoek</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Betaling bevestigd</translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -947,11 +1296,7 @@
<source>Node/Service</source>
<translation>Node/Dienst</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Ping tijd</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -990,6 +1335,32 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 en %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Sla afbeelding op...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Afbeelding kopiëren</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Sla QR-code op</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG afbeelding (*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1194,14 +1565,6 @@
<translation>Maak console leeg</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Verbreek Verbinding Node</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Ban Node voor</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;uur</translation>
</message>
@@ -1218,10 +1581,6 @@
<translation>1 &amp;jaar</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Maak Ban Ongedaan voor Node</translation>
- </message>
- <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Welkom bij de %1 RPC-console.</translation>
</message>
@@ -1352,6 +1711,18 @@
<source>Remove</source>
<translation>Verwijder</translation>
</message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopieer label</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Kopieer bericht</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopieer bedrag</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1371,6 +1742,73 @@
<source>&amp;Save Image...</source>
<translation>&amp;Sla afbeelding op...</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Betalingsverzoek tot %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Betalingsinformatie</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Bedrag</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Bericht</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>Resulterende URI te lang, probeer de tekst korter te maken voor het label/bericht.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Fout tijdens encoderen URI in QR-code</translation>
+ </message>
+</context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Bericht</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen label)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(geen bericht)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(geen bedrag aangevraagd)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Verzoek ingediend</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1407,10 +1845,6 @@
<translation>Bedrag:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioriteit:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Kosten:</translation>
</message>
@@ -1479,10 +1913,6 @@
<translation>(Slimme transactiekosten is nog niet geïnitialiseerd. Dit duurt meestal een paar blokken...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Bevestigings tijd:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normaal</translation>
</message>
@@ -1522,6 +1952,106 @@
<source>S&amp;end</source>
<translation>V&amp;erstuur</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopieer aantal</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopieer bedrag</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopieer vergoeding</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopieer na vergoeding</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopieer bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopieër stof</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopieer wijziging</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 tot %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Weet u zeker dat u wilt verzenden?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>toegevoegd als transactiekosten</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Totaalbedrag %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>of</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Bevestig versturen munten</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Het adres van de ontvanger is niet geldig. Gelieve opnieuw te controleren.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Het ingevoerde bedrag moet groter zijn dan 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Het bedrag is hoger dan uw huidige saldo.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>Het totaal overschrijdt uw huidige saldo wanneer de %1 transactiekosten worden meegerekend.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Dubbel adres gevonden: adressen mogen maar één keer worden gebruikt worden.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Transactiecreatie mislukt</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>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Betalingsverzoek verlopen.</translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Betaal alleen de verplichte transactiekosten van %1</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Waarschuwing: Ongeldig Bitcoinadres</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Waarschuwing: Onbekend wisselgeldadres</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen label)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1601,6 +2131,17 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Vul een label in voor dit adres om het toe te voegen aan uw adresboek</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1699,6 +2240,58 @@
<source>Reset all verify message fields</source>
<translation>Verwijder alles in de invulvelden</translation>
</message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Klik op "Onderteken Bericht" om de handtekening te genereren</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>Het opgegeven adres is ongeldig.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Controleer het adres en probeer het opnieuw.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>Het opgegeven adres verwijst niet naar een sleutel.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Portemonnee-ontsleuteling is geannuleerd.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Geheime sleutel voor het ingevoerde adres is niet beschikbaar.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Ondertekenen van het bericht is mislukt.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Bericht ondertekend.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>De handtekening kon niet worden gedecodeerd.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Controleer de handtekening en probeer het opnieuw.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>De handtekening hoort niet bij het bericht.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Berichtverificatie mislukt.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Bericht geverifiëerd.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1715,11 +2308,440 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Open until %1</source>
+ <translation>Open tot %1</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>geconflicteerd met een transactie met %1 confirmaties</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/offline</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/onbevestigd, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>in geheugenpoel</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>niet in geheugenpoel</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>opgegeven</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/onbevestigd</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 bevestigingen</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Status</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, is nog niet met succes uitgezonden</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Bron</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Gegenereerd</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Van</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>onbekend</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Aan</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>eigen adres</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>alleen-bekijkbaar</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>label</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Credit</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>niet geaccepteerd</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Debet</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Totaal debit</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Totaal credit</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Transactiekosten</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Netto bedrag</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Bericht</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Opmerking</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>Transactie-ID</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Output index</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Handelaar</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>Gegenereerde munten moeten %1 blokken rijpen voordat ze kunnen worden besteed. Toen dit blok gegenereerd werd, werd het uitgezonden naar het netwerk om aan de blokketen toegevoegd te worden. Als het niet lukt om in de keten toegevoegd te worden, zal de status te veranderen naar "niet geaccepteerd" en zal het niet besteedbaar zijn. Dit kan soms gebeuren als een ander knooppunt een blok genereert binnen een paar seconden na die van u.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Debug-informatie</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transactie</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Inputs</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Bedrag</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>waar</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>onwaar</translation>
+ </message>
+</context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Dit venster laat een uitgebreide beschrijving van de transactie zien</translation>
</message>
+ <message>
+ <source>Details for %1</source>
+ <translation>Details voor %1</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Type</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Open tot %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Offline</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Onbevestigd</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Opgegeven</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Bevestigen (%1 van %2 aanbevolen bevestigingen)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Bevestigd (%1 bevestigingen)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>Conflicterend</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Niet beschikbaar (%1 bevestigingen, zal beschikbaar zijn na %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Dit blok is niet ontvangen bij andere nodes en zal waarschijnlijk niet worden geaccepteerd!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Gegenereerd maar niet geaccepteerd</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Ontvangen met</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Ontvangen van</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Verzonden aan</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Betaling aan uzelf</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Gedolven</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>alleen-bekijkbaar</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(nvt)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(geen label)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Transactiestatus. Houd de cursor boven dit veld om het aantal bevestigingen te laten zien.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Datum en tijd waarop deze transactie is ontvangen.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Type transactie.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Of er een alleen-bekijken-adres is betrokken bij deze transactie.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Door gebruiker gedefinieerde intentie/doel van de transactie.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Bedrag verwijderd van of toegevoegd aan saldo.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Alles</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Vandaag</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Deze week</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Deze maand</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Vorige maand</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Dit jaar</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Bereik...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Ontvangen met</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Verzonden aan</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Aan uzelf</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Gedolven</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Anders</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Vul adres of label in om te zoeken</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Min. bedrag</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Doe afstand van transactie</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopieer adres</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopieer label</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopieer bedrag</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopieer transactie-ID</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Kopieer ruwe transactie</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Kopieer volledige transactiedetials</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Bewerk label</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Toon transactiedetails</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exporteer transactiegeschiedenis</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kommagescheiden bestand (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Bevestigd</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Alleen-bekijkbaar</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Type</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Export mislukt</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Er is een fout opgetreden bij het opslaan van de transactiegeschiedenis naar %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Export succesvol</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>De transactiegeschiedenis was succesvol bewaard in %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Bereik:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>naar</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1729,6 +2751,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Er is geen portemonnee geladen.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Verstuur munten</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Exporteer</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Exporteer de data in de huidige tab naar een bestand</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Portemonnee backuppen</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Portemonneedata (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Backup mislukt</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Er is een fout opgetreden bij het wegschrijven van de portemonneedata naar %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Backup succesvol</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>De portemonneedata is succesvol opgeslagen in %1.</translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1763,10 +2834,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>
@@ -1791,16 +2858,12 @@
<translation>Niet mogelijk ok HTTP-server te starten. Zie debuglogboek voor details.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Accepteer verbindingen van buitenaf (standaard: 1 als geen -proxy of -connect is opgegeven)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee is zeer hoog ingesteld! Dit zijn de transactie kosten die u mogelijk betaald wanneer de schattingen niet beschikbaar zijn.</translation>
+ <source>The %s developers</source>
+ <translation>De %s ontwikkelaars</translation>
</message>
<message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
@@ -1823,8 +2886,8 @@
<translation>Verwijder alle transacties van de portemonnee en herstel alleen de delen van de blokketen door -rescan tijdens het opstarten</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Uitgegeven onder de MIT-softwarelicentie, zie het bijgevoegde bestand COPYING of &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
+ <source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
+ <translation>Fout bij het laden van %s: Je kan HD niet activeren voor een reeds bestaande niet-HD portemonnee</translation>
</message>
<message>
<source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
@@ -1835,10 +2898,6 @@
<translation>Voer opdracht uit zodra een portemonneetransactie verandert (%s in cmd wordt vervangen door TxID)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Forceer het doorsturen van transacties van goedgekeurde peers, zelfs wanneer deze niet voldoen aan de lokale doorstuur regels (standaard: %d)</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>
@@ -1851,6 +2910,10 @@
<translation>Waarschuwing: Controleer dat de datum en tijd van uw computer correct zijn ingesteld! Bij een onjuist ingestelde klok zal %s niet goed werken.</translation>
</message>
<message>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
+ <translation>Gelieve bij te dragen als je %s nuttig vindt. Bezoek %s voor meer informatie over de software.</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>
@@ -1859,30 +2922,22 @@
<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 prerelease testversie – gebruik op eigen risico! Gebruik deze niet voor het delven van munten of handelsdoeleinden</translation>
+ <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>
<message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<translation>Gebruik UPnP om de luisterende poort te mappen (standaard: 1 als er geluisterd worden en geen -proxy is meegegeven)</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>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Goedgekeurde peers die verbinden van het ingegeven netmask of IP adres. Kan meerdere keren gespecificeerd worden.</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>
<message>
+ <source>%s corrupt, salvage failed</source>
+ <translation>%s corrupt, veiligstellen mislukt</translation>
+ </message>
+ <message>
<source>-maxmempool must be at least %d MB</source>
<translation>-maxmempool moet tenminste %d MB zijn</translation>
</message>
@@ -1911,10 +2966,6 @@
<translation>Wijzigingsindex buiten bereik</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Verbind alleen naar de gespecificeerde node(s)</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Verbindingsopties:</translation>
</message>
@@ -1979,6 +3030,10 @@
<translation>Fout bij laden %s: Portemonnee vereist een nieuwere versie van %s</translation>
</message>
<message>
+ <source>Error loading %s: You can't disable HD on a already existing HD wallet</source>
+ <translation>Fout bij het laden van %s: Je kan HD niet deactiveren voor een reeds bestaande HD portemonnee</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>Fout bij het laden van blokkendatabase</translation>
</message>
@@ -2031,10 +3086,6 @@
<translation>Locatie van de auth cookie (standaard: data dir)</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>Minimum aantal bytes dat er per sigop in een transactie gerelayed en gemined worden (standaard: %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>Niet genoeg file descriptors beschikbaar.</translation>
</message>
@@ -2067,6 +3118,10 @@
<translation>Herbouw ketenstaat vanuit de huidige geindexeerde blokken</translation>
</message>
<message>
+ <source>Rewinding blocks...</source>
+ <translation>Blokken aan het terugdraaien...</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>Zet database cache grootte in megabytes (%d tot %d, standaard: %d)</translation>
</message>
@@ -2079,6 +3134,10 @@
<translation>Specificeer het portemonnee bestand (vanuit de gegevensmap)</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation>De broncode is beschikbaar van %s.</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer. %s is probably already running.</source>
<translation>Niet in staat om %s te verbinden op deze computer. %s draait waarschijnlijk al.</translation>
</message>
@@ -2171,10 +3230,6 @@
<translation>Maximale grootte va n de gegevens in gegevensdragertransacties die we doorgeven en mijnen (standaard: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Query voor peeradressen via DNS- lookup , als laag op adressen (standaard: 1 unless -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Gebruik willekeurige inloggegevens voor elke proxyverbinding. Dit maakt streamislatie voor Tor mogelijk (standaard: %u)</translation>
</message>
@@ -2187,8 +3242,8 @@
<translation>Het transactiebedrag is te klein om te versturen nadat de transactiekosten in mindering zijn gebracht</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Dit product bevat software dat ontwikkeld is door het OpenSSL Project voor gebruik in de OpenSSL Toolkit &lt;https://www.openssl.org/&gt; en cryptografische software geschreven door Eric Young en UPnP software geschreven door Thomas Bernard.</translation>
+ <source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
+ <translation>Gebruik hiërarchische deterministische sleutelgeneratie (HD) na BIP32. Dit heeft enkel effect bij het aanmaken van portemonnees of het eerste gebruik</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>
@@ -2196,7 +3251,7 @@
</message>
<message>
<source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
- <translation>U moet de database herbouwen met -reindex om terug te gaan naar de ongesnoeide modus. Dit zal de gehele blokkketen opnieuw downloaden.</translation>
+ <translation>U moet de database herbouwen met -reindex om terug te gaan naar de ongesnoeide modus. Dit zal de gehele blokketen opnieuw downloaden.</translation>
</message>
<message>
<source>(default: %u)</source>
@@ -2299,10 +3354,6 @@
<translation>Transactiebedrag te klein</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Transactiebedragen moeten positief zijn</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>De transactie is te groot voor het transactiekostenbeleid</translation>
</message>
@@ -2367,18 +3418,22 @@
<translation>-maxtxfee staat zeer hoog! Transactiekosten van de grootte kunnen worden gebruikt in een enkele transactie.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee staat zeer hoog! Dit is de transactiekosten die u betaalt als u een transactie doet.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Bewaar transactie niet langer dan &lt;n&gt; uren in de geheugenpool (standaard: %u)</translation>
</message>
<message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Equivalent byter per sigop in transactions voor doorsturen en mijnen (standaard: %u)</translation>
+ </message>
+ <message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation>Transactiekosten (in %s/kB) kleiner dan dit worden beschouwd dat geen transactiekosten in rekening worden gebracht voor transactiecreatie (standaard: %s)</translation>
</message>
<message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>Forceer het doorsturen van transacties van goedgekeurde peers, zelfs wanneer deze niet voldoen aan de lokale doorstuurregels (standaard: %d)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>Hoe grondig de blokverificatie van -checkblocks is (0-4, standaard: %u)</translation>
</message>
@@ -2419,10 +3474,6 @@
<translation>Gebruik een aparte SOCKS5 proxy om verborgen diensten van Tor te bereiken (standaard: %s)</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. 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. Deze optie kan meerdere keren worden meegegeven</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>Waarschuwing: Onbekende blok versies worden gemined! Er zijn mogelijk onbekende regels in werking getreden</translation>
</message>
@@ -2491,8 +3542,8 @@
<translation>Stel sleutelpoelgrootte in op &lt;n&gt; (standaard: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Stel minimum blokgrootte in in bytes (standaard: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Zet het BIP141 maximum gewicht van een blok (standaard: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
@@ -2515,6 +3566,10 @@
<translation>Besteed onbevestigd wisselgeld bij het doen van transacties (standaard: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Netwerkthread starten...</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>
diff --git a/src/qt/locale/bitcoin_pam.ts b/src/qt/locale/bitcoin_pam.ts
index 5351543338..f09978f6b0 100644
--- a/src/qt/locale/bitcoin_pam.ts
+++ b/src/qt/locale/bitcoin_pam.ts
@@ -33,7 +33,10 @@
<source>&amp;Delete</source>
<translation>&amp;Ilako</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -52,7 +55,7 @@
<source>Repeat new passphrase</source>
<translation>Pasibayuan ya ing bayung passphrase</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -222,7 +225,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Maka-&lt;b&gt;encrypt&lt;/b&gt; ya ing wallet at kasalukuyan yang maka-&lt;b&gt;locked&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -256,7 +259,7 @@
<source>&amp;Address</source>
<translation>&amp;Address</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -291,6 +294,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Tatauling oras na ning block</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -412,6 +426,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -426,6 +443,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>N/A</source>
@@ -511,6 +534,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -552,7 +578,7 @@
<source>S&amp;end</source>
<translation>Ipadala</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -589,6 +615,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -657,7 +686,7 @@
<source>Reset all verify message fields</source>
<translation>Ibalik king dati reng ngan fields na ning pamag beripikang mensayi</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -669,16 +698,34 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Ining pane a ini magpakit yang detalyadung description ning transaksion</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -705,10 +752,6 @@
<translation>Gumana king gulut bilang daemon at tumanggap commands</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Tumanggap koneksion menibat king kilwal (default: 1 if no -proxy or -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Kapilubluban ning Bitcoin</translation>
</message>
@@ -717,10 +760,6 @@
<translation>Pipamilian king pamag-gawang block:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Kumunekta mu king mepiling node(s)</translation>
- </message>
- <message>
<source>Corrupted block database detected</source>
<translation>Mekapansin lang me-corrupt a block database</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts
index 09f748b83c..4634814070 100644
--- a/src/qt/locale/bitcoin_pl.ts
+++ b/src/qt/locale/bitcoin_pl.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>&amp;Usuń</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Wybierz adres, na który chcesz wysłać monety</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Wybierz adres, na który chcesz otrzymać monety</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>W&amp;ybierz</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Adresy wysyłania</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Adresy odbioru</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>Tutaj znajdują się adresy Bitcoin na które wysyłasz płatności. Zawsze sprawdzaj ilość i adres odbiorcy przed wysyłką monet.</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>To są twoje adresy Bitcoin do odbierania płatności. Zaleca się używanie nowych adresów odbiorczych dla każdej transakcji.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopiuj adres</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopiuj &amp;Etykietę</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Edytuj</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Eksportuj listę adresów</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Plik *.CSV (dane rozdzielane przecinkami)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksportowanie nie powiodło się</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Wystąpił błąd podczas próby zapisu listy adresów do %1. Proszę spróbować ponownie.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etykieta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(brak etykiety)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>Powtórz nowe hasło</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>Wprowadź nowe hasło do portfela.&lt;br/&gt;Proszę używać hasła złożonego z &lt;b&gt;10 lub więcej losowych znaków&lt;/b&gt; albo &lt;b&gt;8 lub więcej słów.&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Zaszyfruj portfel</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Ta operacja wymaga hasła do portfela aby odblokować portfel.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Odblokuj portfel</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Ta operacja wymaga hasła portfela, aby go odszyfrować.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Odszyfruj portfel</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Zmień hasło</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Podaj stare i nowe hasło do portfela.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <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>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Odblokowanie portfela nie powiodło się</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Wprowadzone hasło do odszyfrowania portfela jest niepoprawne.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Odszyfrowanie portfela nie powiodło się</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Hasło do portfela zostało pomyślnie zmienione.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Ostrzeżenie: Caps Lock jest włączony!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -270,34 +429,10 @@
<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>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n godzin</numerusform><numerusform>%n godzin</numerusform><numerusform>%n godzin</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>dzień</numerusform><numerusform>%n dni</numerusform><numerusform>%n dni</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n tygodni</numerusform><numerusform>%n tygodni</numerusform><numerusform>%n tygodni</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 i %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n lat</numerusform><numerusform>%n lat</numerusform><numerusform>%n lat</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 za</translation>
@@ -384,7 +519,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -404,10 +539,6 @@
<translation>Kwota:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorytet:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Opłata:</translation>
</message>
@@ -460,8 +591,84 @@
<translation>Potwierdzony</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Priorytet</translation>
+ <source>Copy address</source>
+ <translation>Kopiuj adres</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiuj etykietę</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiuj kwotę</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Skopiuj ID transakcji</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Zablokuj niewydane</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Odblokuj niewydane</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Skopiuj ilość</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Skopiuj prowizję</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Skopiuj ilość po opłacie</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Skopiuj ilość bajtów</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopiuj pył</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Skopiuj resztę</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 zablokowane)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>tak</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>Ta etykieta staje się czerwona jeżeli którykolwiek odbiorca otrzymuje kwotę mniejszą niż obecny próg pyłu.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Waha się +/- %1 satoshi na wejście.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(brak etykiety)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>reszta z %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(reszta)</translation>
</message>
</context>
<context>
@@ -486,6 +693,30 @@
<source>&amp;Address</source>
<translation>&amp;Adres</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nowy adres odbiorczy</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nowy adres wysyłania</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Zmień adres odbioru</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Zmień adres wysyłania</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Nie można było odblokować portfela.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Generowanie nowego klucza nie powiodło się.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -609,6 +840,49 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formularz</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Pozostało bloków</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Nienznane...</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Czas ostatniego bloku</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>Postęp</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Przyrost postępu na godzinę</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>obliczanie...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Przewidywany czas zakończenia synchronizacji</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Ukryj</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Nieznane. Synchronizowanie nagłówków (%1)...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -626,6 +900,10 @@
<source>Select payment request file</source>
<translation>Otwórz żądanie zapłaty z pliku</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Wybierz plik żądania zapłaty do otwarcia</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -938,6 +1216,57 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Błąd żądania płatności</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Nie można uruchomić protokołu bitcoin: kliknij-by-zapłacić</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Obsługa URI</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>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>
<source>User Agent</source>
@@ -948,8 +1277,12 @@
<translation>Węzeł/Usługi</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Czas odpowiedzi</translation>
+ <source>NodeId</source>
+ <translation>Identyfikator węzła</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
</message>
</context>
<context>
@@ -990,6 +1323,44 @@
<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></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minuta</numerusform><numerusform>%n minut</numerusform><numerusform>%n minut</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 i %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ <message>
+ <source>Error: %1</source>
+ <translation>Błąd: %1</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <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>
@@ -1142,10 +1513,18 @@
<translation>Czas odpowiedzi</translation>
</message>
<message>
+ <source>The duration of a currently outstanding ping.</source>
+ <translation>Czas trwania nadmiarowego pingu</translation>
+ </message>
+ <message>
<source>Ping Wait</source>
<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>
@@ -1190,14 +1569,6 @@
<translation>Wyczyść konsolę</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>Odłącz Nod</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Blokuj węzeł na okres</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;godzina</translation>
</message>
@@ -1214,8 +1585,16 @@
<translation>1 &amp;rok</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>Odblokuj węzeł</translation>
+ <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>
@@ -1348,6 +1727,22 @@
<source>Remove</source>
<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>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1367,6 +1762,61 @@
<source>&amp;Save Image...</source>
<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>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etykieta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Wiadomość</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(brak etykiety)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(brak wiadomości)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Zażądano</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1403,10 +1853,6 @@
<translation>Kwota:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorytet:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Opłata:</translation>
</message>
@@ -1475,10 +1921,6 @@
<translation>(Sprytne opłaty nie są jeszcze zainicjowane. Trwa to zwykle kilka bloków...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Czas potwierdzenia:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normalnie</translation>
</message>
@@ -1503,6 +1945,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>
@@ -1518,6 +1964,70 @@
<source>S&amp;end</source>
<translation>Wy&amp;syłka</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Skopiuj ilość</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiuj kwotę</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Skopiuj prowizję</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Skopiuj ilość po opłacie</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Skopiuj ilość bajtów</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopiuj pył</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Skopiuj resztę</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 do %2</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>lub</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>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>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1597,6 +2107,13 @@
<source>Memo:</source>
<translation>Notatka:</translation>
</message>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Tak</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1696,7 +2213,23 @@ 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>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>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1712,12 +2245,173 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Źródło</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Wygenerowano</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Od</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>nieznane</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Do</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>własny adres</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>tylko-obserwowany</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etykieta</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Wiadomość</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kwota</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Ten panel pokazuje szczegółowy opis transakcji</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etykieta</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Offline</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Niepotwierdzone</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Porzucone</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>Skonfliktowane</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Wygenerowane ale nie zaakceptowane</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Wysłane do</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>tylko-obserwowany</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(brak etykiety)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Wszystko</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Dzisiaj</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>W tym tygodniu</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>W tym miesiącu</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>W zeszłym miesiącu</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>W tym roku</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Zakres...</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Wysłane do</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopiuj adres</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiuj etykietę</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiuj kwotę</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Skopiuj ID transakcji</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Plik *.CSV (dane rozdzielane przecinkami)</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etykieta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksportowanie nie powiodło się</translation>
+ </message>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1726,6 +2420,15 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1756,6 +2459,14 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Przycinanie skonfigurowano poniżej minimalnych %d MiB. Proszę użyć wyższej liczby.</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>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>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>
+ <message>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
<translation>Błąd: Wystąpił fatalny błąd wewnętrzny, sprawdź szczegóły w debug.log</translation>
</message>
@@ -1776,10 +2487,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Uruchomienie serwera HTTP nie powiodło się. Zobacz dziennik debugowania, aby uzyskać więcej szczegółów.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Akceptuj połączenia z zewnątrz (domyślnie: 1 jeśli nie ustawiono -proxy lub -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Rdzeń Bitcoina</translation>
</message>
@@ -1788,8 +2495,12 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Deweloperzy %s</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee ma ustawioną bardzo dużą wartość! Jest to prowizja za transakcje, którą możesz zapłacić gdy oszacowanie opłaty jest niemożliwe.</translation>
+ <source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
+ <translation>Stawka prowizji (w %s/kB), która będzie użyta, gdy oszacowane dane o prowizjach nie będą wystarczające (domyślnie: %s)</translation>
+ </message>
+ <message>
+ <source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
+ <translation>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</translation>
</message>
<message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
@@ -1804,10 +2515,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Usuwa wszystkie transakcje w portfelu i tylko odtwarza te części z łańcucha bloków poprzez -rescan przy starcie</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Rozprowadzane na licencji MIT, zobacz dołączony plik COPYING lub &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</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>Błąd odczytu %s! Wszystkie klucze zostały odczytane poprawnie, ale może brakować danych transakcji lub wpisów w książce adresowej, lub mogą one być nieprawidłowe.</translation>
</message>
@@ -1816,10 +2523,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Wykonaj polecenie, kiedy transakcja portfela ulegnie zmianie (%s w poleceniu zostanie zastąpione przez TxID)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Wymuś przekazywanie transakcji od osób z białej listy, nawet jeśli narusza to lokalną politykę przekazywania (default: %d)</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>
<translation>Proszę sprawdzić czy data i czas na Twoim komputerze są poprawne! Jeżeli ustawienia zegara będą złe, %s nie będzie działał prawidłowo.</translation>
</message>
@@ -1828,26 +2531,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Ustaw liczbę wątków skryptu weryfikacyjnego (%u do %d, 0 = auto, &lt;0 = zostaw tyle rdzeni wolnych, domyślnie: %d)</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>To jest testowa wersja - używaj na własne ryzyko - nie używaj do wykopywania oraz przy aplikacjach kupieckich</translation>
- </message>
- <message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<translation>Użyj UPnP do mapowania portu nasłuchu (domyślnie: 1 gdy nasłuchuje i brak -proxy)</translation>
</message>
<message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Ostrzeżenie: Sieć nie wydaje się w pełni zgodna! Niektórzy górnicy wydają się doświadczać problemów.</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>Uwaga: Wygląda na to, że nie ma pełnej zgodności z naszymi peerami! Możliwe, że potrzebujesz aktualizacji bądź inne węzły jej potrzebują</translation>
- </message>
- <message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Dodawaj do białej listy węzły łączące się z podanej maski sieciowej lub adresu IP. Może być określona kilka razy.</translation>
- </message>
- <message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation>Musisz przebudować bazę używając -reindex-chainstate aby zmienić -txindex</translation>
</message>
@@ -1864,6 +2551,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>&lt;category&gt; mogą być:</translation>
</message>
<message>
+ <source>Append comment to the user agent string</source>
+ <translation>Dodaj komentarz do pola user agent</translation>
+ </message>
+ <message>
<source>Attempt to recover private keys from a corrupt wallet on startup</source>
<translation>Próbuj odzyskać klucze prywatne z uszkodzonego portfela podczas uruchamiania.</translation>
</message>
@@ -1872,8 +2563,8 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Opcje tworzenia bloku:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Łącz się tylko do wskazanego węzła/węzłów</translation>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>Nie można rozpoznać -%s adresu: '%s'</translation>
</message>
<message>
<source>Connection options:</source>
@@ -1968,6 +2659,14 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Utrzymuj obszar pamięci dla transakcji poniżej &lt;n&gt; MB (default: %u)</translation>
</message>
<message>
+ <source>Loading banlist...</source>
+ <translation>Ładowanie listy zablokowanych...</translation>
+ </message>
+ <message>
+ <source>Location of the auth cookie (default: data dir)</source>
+ <translation>Lokalizacja autoryzacyjnego pliku cookie (domyślnie: ścieżka danych)</translation>
+ </message>
+ <message>
<source>Not enough file descriptors available.</source>
<translation>Brak wystarczającej liczby deskryptorów plików. </translation>
</message>
@@ -2012,6 +2711,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Określ plik portfela (w obrębie folderu danych)</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation>Kod źródłowy dostępny jest z %s.</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer. %s is probably already running.</source>
<translation>Nie można przywiązać do %s na tym komputerze. %s prawdopodobnie jest już uruchomiony.</translation>
</message>
@@ -2088,6 +2791,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>
@@ -2100,10 +2807,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Maksymalny rozmiar danych w transakcji przekazującej dane które przekazujemy i wydobywamy (domyślnie: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Wyszukaj adresy węzłów wykorzystując zapytanie DNS, jeżeli masz mało adresów (domyślnie: 1 jeśli nie użyto -connect)</translation>
- </message>
- <message>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
<translation>Ustaw maksymalny rozmiar transakcji o wysokim priorytecie/niskiej prowizji w bajtach (domyślnie: %d)</translation>
</message>
@@ -2112,8 +2815,8 @@ 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>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Program ten zawiera oprogramowanie stworzone przez OpenSSL Project do użycia w OpensSSL Toolkit &lt;https://www.openssl.org/&gt;, oprogramowanie kryptograficzne napisane przez Eric Young oraz oprogramowanie UPnP napisane przez Thomas Bernard.</translation>
+ <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>
@@ -2212,12 +2915,12 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Hasło zabezpieczające portu kontrolnego Tora (domyślnie: puste)</translation>
</message>
<message>
- <source>Transaction amount too small</source>
- <translation>Zbyt niska kwota transakcji </translation>
+ <source>Tor control port to use if onion listening enabled (default: %s)</source>
+ <translation>Port kontrolny sieci Tor jeśli onion listening jest włączone (domyślnie: %s)</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Kwota transakcji musi być dodatnia</translation>
+ <source>Transaction amount too small</source>
+ <translation>Zbyt niska kwota transakcji </translation>
</message>
<message>
<source>Transaction too large for fee policy</source>
@@ -2276,10 +2979,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>-maxtxfee ma ustawioną badzo dużą wartość! Tak wysokie opłaty mogą być zapłacone w jednej transakcji.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee ma ustawioną bardzo dużą wartość! Jest to prowizja za transakcje, którą płacisz, gdy wysyłasz monety.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Nie trzymaj w pamięci transakcji starszych niż &lt;n&gt; godz. (domyślnie: %u)</translation>
</message>
@@ -2332,6 +3031,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Ostrzeżenie: Odtworzono dane z uszkodzonego pliku portfela! Oryginalny %s został zapisany jako %s w %s; jeśli twoje saldo lub transakcje są niepoprawne powinieneś odtworzyć kopię zapasową.</translation>
</message>
<message>
+ <source>%s is set very high!</source>
+ <translation>%s jest ustawione bardzo wysoko!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(domyślnie: %s)</translation>
</message>
@@ -2392,10 +3095,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Ustaw rozmiar puli kluczy na &lt;n&gt; (domyślnie: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Ustaw minimalny rozmiar bloku w bajtach (domyślnie: %u)</translation>
- </message>
- <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>Ustaw liczbę wątków do obsługi RPC (domyślnie: %d)</translation>
</message>
@@ -2420,6 +3119,14 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Próg, po którym nastąpi rozłączenie węzłów nietrzymających się zasad (domyślnie: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Kwota transakcji musi być dodatnia</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>Transakcja wymaga co najmniej jednego odbiorcy</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Nieznana sieć w -onlynet: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts
index ee48c67341..3202587cbd 100644
--- a/src/qt/locale/bitcoin_pt_BR.ts
+++ b/src/qt/locale/bitcoin_pt_BR.ts
@@ -39,7 +39,78 @@
</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>
+ <translation>Escoha o endereço para enviar moedas</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Escolha o enereço para receber moedas</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>Escol&amp;ha</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Endereços de envio</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Endereços de recebimento</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>Estes são os seus endereços para enviar pagamentos. Sempre cheque a quantia e o endereço do destinatário 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 para receber pagamentos. É recomendado usar um novo para cada transação.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Copiar endereço</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copiar rótu&amp;lo</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Editar</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exportar lista de endereços</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Comma separated file (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Falha na exportação</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Erro ao salvar a lista de endereço para %1. Tente novamente.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Rótulo</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Endereço</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sem rótulo)</translation>
</message>
</context>
<context>
@@ -60,6 +131,90 @@
<source>Repeat new passphrase</source>
<translation>Repita a nova frase de segurança</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>Insira a nova senha para a carteira.&lt;br/&gt;Favor usar uma senha com &lt;b&gt;dez ou mais caracteres aleatórios&lt;/b&gt;, ou &lt;b&gt;oito ou mais palavras&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Criptografar carteira</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Esta operação precisa da sua senha para desbloquear a carteira.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Desbloquear carteira</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Esta operação precisa da sua senha para descriptografar a carteira</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Descriptografar carteira</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Alterar senha</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Insira a senha antiga e a nova para a carteira.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Confirmar criptografia da carteira</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>Aviso: Se você criptografar sua carteira e perder sua senha, você vai &lt;b&gt;PERDER TODOS OS SEUS BITCOINS&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Tem certeza que deseja criptografar a carteira?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Carteira criptografada</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 backup prévio que você tenha feito da sua carteira deve ser substituído pelo novo e encriptado arquivo gerado. Por razões de segurança, qualquer backup do arquivo não criptografado se tornará inútil assim que você começar a usar uma nova carteira criptografada.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Falha ao criptografar carteira</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Falha na criptografia devido a um erro inerno. Sua carteira não foi criptografada.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>As senhas não conferem.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Falha ao desbloquear carteira</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>A senha inserida para descriptografar a carteira está incorreta.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Falha ao descriptografar a carteira</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>A senha da carteira foi alterada com êxito.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Aviso: Tecla Caps Lock ativa!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -76,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>
@@ -159,6 +314,22 @@
<translation>Abrir &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Clique para desativar a atividade de rede.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Atividade de rede desativada.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <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>
@@ -176,7 +347,7 @@
</message>
<message>
<source>&amp;Debug window</source>
- <translation>Janela de &amp;Depuração</translation>
+ <translation>Janela de &amp;depuração</translation>
</message>
<message>
<source>Open debugging and diagnostic console</source>
@@ -204,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>
@@ -270,34 +441,10 @@
<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>
</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>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n ano</numerusform><numerusform>%n anos</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 atrás</translation>
@@ -332,7 +479,11 @@
</message>
<message>
<source>%1 client</source>
- <translation>cliente %1</translation>
+ <translation>%1 cliente</translation>
+ </message>
+ <message>
+ <source>Connecting to peers...</source>
+ <translation>Conectando...</translation>
</message>
<message>
<source>Catching up...</source>
@@ -377,6 +528,14 @@
<translation>Transação recebida</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>Geração de chave HD está &lt;b&gt;ativada&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>Geração de chave HD está &lt;b&gt;desativada&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>Carteira está &lt;b&gt;criptografada&lt;/b&gt; e atualmente &lt;b&gt;desbloqueada&lt;/b&gt;</translation>
</message>
@@ -384,6 +543,10 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Carteira está &lt;b&gt;criptografada&lt;/b&gt; e atualmente &lt;b&gt;bloqueada&lt;/b&gt;</translation>
</message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Um erro fatal ocorreu. Bitcoin não pode continuar em segurança e irá fechar.</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -404,10 +567,6 @@
<translation>Quantia:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridade:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Taxa:</translation>
</message>
@@ -441,11 +600,11 @@
</message>
<message>
<source>Received with label</source>
- <translation>Recebido com rótulo</translation>
+ <translation>Rótulo</translation>
</message>
<message>
<source>Received with address</source>
- <translation>Recebido com endereço </translation>
+ <translation>Endereço </translation>
</message>
<message>
<source>Date</source>
@@ -460,8 +619,84 @@
<translation>Confirmado</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Prioridade</translation>
+ <source>Copy address</source>
+ <translation>Copiar endereço</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar rótulo</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar quantia</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copiar ID da transação</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Boquear saída</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Desboquear saída</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copiar quantia</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copiar taxa</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copiar pós taxa</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <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>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 bloqueada)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>sim</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <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>Este texto fica vermelho se qualquer destinatário receber uma quantidade menor que que o dust.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Pode variar +/- %1 satoshi(s) por entrada</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sem rótulo)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>troco de %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(troco)</translation>
</message>
</context>
<context>
@@ -486,6 +721,38 @@
<source>&amp;Address</source>
<translation>&amp;Endereço</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Novo endereço de recebimento</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Novo endereço de envio</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Editar endereço de recebimento</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Editar endereço de envio</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>O endereço digitado "%1" não é um endereço válido.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>O endereço digitado "%1" já se encontra no catálogo de endereços.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Não foi possível desbloquear a carteira</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Falha ao gerar chave</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -609,6 +876,57 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <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 estar visíveis ainda, portanto o seu saldo pode estar incorreto. Esta informação será corrigida assim que sua carteira for sincronizada com a rede, como detalhado abaixo.</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>Gastar moedas de transações desconhecidas podem não ser aceitas pela rede.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Número de blocos restantes</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Desconhecido...</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Horário do último bloco</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>Progresso</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Aumento do progresso por hora</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>calculando...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Tempo estimado para sincronizar</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Ocultar</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Desconhecido. Sincroniando cabeçahos (%1)...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -626,6 +944,10 @@
<source>Select payment request file</source>
<translation>Selecione o arquivo de cobrança</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Selecione o arquivo de cobrança para ser aberto</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -643,7 +965,7 @@
</message>
<message>
<source>&amp;Start %1 on system login</source>
- <translation>$Iniciar %1 ao fazer login no sistema</translation>
+ <translation>&amp;Iniciar %1 ao fazer login no sistema</translation>
</message>
<message>
<source>Size of &amp;database cache</source>
@@ -938,6 +1260,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Erro no pedido de pagamento</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Não foi possível iniciar bitcoin: manipulador click-to-pay</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Manipulação de URI</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>URL de cobrança é inválida: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Endereço de pagamento %1 inválido</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 pode ser analisado! Isto pode ser causado por um endereço inválido ou parâmetros URI informados incorretamente.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Manipulação de arquivo de cobrança</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>Arquivo de pedido de pagamento não pode ser lido! Isto pode ser causado por uma requisição de pagamento inválida.</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 do pedido de pagamento não corresponde rede do cliente.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Pedido de pagamento expirado</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Pedido de pagamento não 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>Valor do pagamento solicitado de %1 é muito pequeno (Considerado poeira).</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 é muito grande (%2 bytes, permitido %3 bytes).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Erro na comunicação com %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Pedido de pagamento não pode ser analisado!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Erro na resposta do servidor: %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Erro de solicitação de rede</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Pagamento reconhecido</translation>
+ </message>
+</context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -948,7 +1361,11 @@
<translation>Nó/Serviço</translation>
</message>
<message>
- <source>Ping Time</source>
+ <source>NodeId</source>
+ <translation>ID do nó</translation>
+ </message>
+ <message>
+ <source>Ping</source>
<translation>Ping</translation>
</message>
</context>
@@ -990,6 +1407,72 @@
<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>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n ano</numerusform><numerusform>%n anos</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 ainda não terminou com segurança...</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Erro: diretório de dados especificado "%1" não existe.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>Erro: Não foi possível interpretar arquivo de configuração: %1. Utilize apenas a sintaxe chave=valor.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Erro: %1</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Savar imagem</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Copiar imagem</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Salvar código QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Imagem PNG (*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1150,6 +1633,10 @@
<translation>Espera de ping</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Ping min</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Offset de tempo</translation>
</message>
@@ -1187,21 +1674,13 @@
</message>
<message>
<source>Debug log file</source>
- <translation>Arquivo de log de Depuração</translation>
+ <translation>Arquivo de log de depuração</translation>
</message>
<message>
<source>Clear console</source>
<translation>Limpar console</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Desconectar Nó</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Banir nó por</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;hora</translation>
</message>
@@ -1218,8 +1697,16 @@
<translation>1 &amp;ano</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Desbanir nó</translation>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Desconectar</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Banir por</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Desbanir</translation>
</message>
<message>
<source>Welcome to the %1 RPC console.</source>
@@ -1234,6 +1721,14 @@
<translation>Digite &lt;b&gt;help&lt;/b&gt; para uma visão geral dos 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: Scammers atacam essa área, dizendo aos usuários que comandos digitar aqui, roubando informações da carteira. Não use este console sem entender completamente as ramificações do comando.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Atividade da rede disativada</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1352,6 +1847,22 @@
<source>Remove</source>
<translation>Remover</translation>
</message>
+ <message>
+ <source>Copy URI</source>
+ <translation>Copiar URI</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar rótulo</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Copiar mensagem</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar quantia</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1371,6 +1882,73 @@
<source>&amp;Save Image...</source>
<translation>&amp;Salvar Imagem...</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Pedido de pagamento para %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informação do pagamento</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Endereço</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Quantia</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Rótulo</translation>
+ </message>
+ <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 longa. Tente reduzir o texto do rótulo ou da mensagem.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Erro ao codigicar o 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>Rótulo</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mensagem</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sem rótulo)</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(sem mensagem)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(nenhuma quantia solicitada)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Solicitado</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1407,10 +1985,6 @@
<translation>Quantia:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridade:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Taxa:</translation>
</message>
@@ -1479,10 +2053,6 @@
<translation>(Smart fee não iniciado. Isso requer alguns blocos...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Tempo de confirmação:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1507,6 +2077,10 @@
<translation>Poeira:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Confirmando tempo alvo:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Limpar Tudo</translation>
</message>
@@ -1522,6 +2096,126 @@
<source>S&amp;end</source>
<translation>Enviar</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copiar quantia</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar quantia</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copiar taxa</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copiar pós taxa</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <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>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 a %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Tem certeza que deseja enviar?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>adicionado como taxa da transação </translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Quantia tota %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>ou</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Confirme o envio de moedas</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Endereço de envio inváido. Favor checar.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>A quantia à pagar deve ser maior que 0</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>A quantia 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 da transação %1 é incluída</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Endereço duplicado encontrado: Endereços devem ser usados somente uma vez cada.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Falha na criação da transação</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>A transação foi negada pela seguinte razão: %1</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Uma taxa maior que %1 é considerada uma taxa absurdamente alta.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Pedido de pagamento expirado</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n bloco</numerusform><numerusform>%n blocos</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Pagar somente a taxa requerida de %1</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Confirmação em %n bloco.</numerusform><numerusform>Confirmação em %n blocos.</numerusform></translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Aviso: Endereço inválido</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Aviso: Endereço de troco inválido</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <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ótulo)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1567,7 +2261,7 @@
</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>A taxa será deduzida da quantia sendo enviada. O destinatário receberá menos bitcoins do que você colocou no campo de quantidade. Se varios destinatários estão selecionados, a taxa é dividida igualmente.</translation>
+ <translation>A taxa será deduzida da quantia que está sendo enviada. O destinatário receberá menos bitcoins do que você colocou no campo de quantidade. Se vários destinatários estão selecionados, a taxa é dividida igualmente.</translation>
</message>
<message>
<source>S&amp;ubtract fee from amount</source>
@@ -1601,10 +2295,25 @@
<source>Memo:</source>
<translation>Memorizar:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Digite um rótulo para este endereço para adicioná-lo ao catálogo de endereços</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Sim</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down...</source>
+ <translation>%1 está desligando...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation>Não desligue o computador até que esta janela desapareça.</translation>
</message>
@@ -1695,6 +2404,58 @@
<source>Reset all verify message fields</source>
<translation>Limpar todos os campos de assinatura da mensagem</translation>
</message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Clique em "Assinar mensagem" para gerar a assinatura</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>O endereço digitado é inválido</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Favor checar o endereço e tente novamente</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>O endereço fornecido não se refere a uma 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 do endereço inserido não está disponível</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Falha ao assinar mensagem</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Mensagem assinada</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>A assinatura não pode ser descodificada</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Favor checar a assinatura e tente novamente</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>A assinatura não corresponde a mensagem</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Falha na verificação da mensagem</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Mensagem verificada</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1711,11 +2472,460 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Abrir para mais %n bloco</numerusform><numerusform>Abrir para mais %n blocos</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Aberto até %1</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>conflitado com uma transação com %1 confirmações</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/offline</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/não confirmado, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>na memória</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>não na memóra</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>abandonado</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/não confirmado</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 confirmações</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Status</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, ainda não foi propagada na rede com êxito.</translation>
+ </message>
+ <message numerus="yes">
+ <source>, broadcast through %n node(s)</source>
+ <translation><numerusform>, transmitido aravés de %n nó</numerusform><numerusform>, transmitido aravés de %n nós</numerusform></translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Fonte</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>próprio endereço</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>monitorado</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>rótulo</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Crédito</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>maduro em mais %n bloco</numerusform><numerusform>maduro em mais %n blocos</numerusform></translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>não aceito</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 da 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 tota da transação</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Index da saída</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Mercador</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>Moedas recém minerados precisam aguardar %1 blocos antes de serem gastos. Quando o bloco foi gerado, ele foi disseminado pela rede para ser adicionado à blockchain. Se ele falhar em ser inserido na cadeia, seu estado será modificado para "não aceito" e ele não poderá ser gasto. Isso pode acontecer eventualmente quando blocos são gerados quase que simultaneamente.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Depurar informaçã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>Quantia</translation>
+ </message>
+ <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>Este painel mostra uma descrição detalhada da transação</translation>
</message>
+ <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>Rótulo</translation>
+ </message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Aberto por mais %n bloco</numerusform><numerusform>Aberto por mais %n blocos</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Aberto até %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Offline</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Não confirmado</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Abandonado</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Confirmando (%1 de %2 confirmações recomendadas)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Confirmado (%1 confirmações)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>Conflitado</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Recém-criado (%1 confirmações, disponível somente após %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Este bloco não foi recebido por nenhum outro participante da rede e provavelmente não será aceito!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Gerado mas não aceito</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Recebido</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Recebido</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviado para</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Pagamento para você mesmo</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minerado</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>monitorado</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/a)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sem rótulo)</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Status da transação. Passe o mouse sobre este campo para mostrar o número de confirmações.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Data e hora em que a transação foi recebida.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Tipo de transação</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Mostrar ou não endereços monitorados na lista de transações.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Intenção/Propósito definido pelo usuário para a transação</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Quantidade debitada ou creditada ao saldo.</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Todos</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Hoje</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Essa semana</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Esse mês</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Último mês</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Este ano</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Intervalo...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Recebido</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviado para</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Para você mesmo</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minerado</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Outro</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Procure um endereço ou rótulo</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Quantia mínima</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Transação abandonada</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Copiar endereço</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar rótulo</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar quantia</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copiar ID da transação</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Copiar o raw da transação</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Copiar dados completos da transação</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Editar rótulo</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 transações</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Comma separated file (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Confirmado</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Monitorado</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipo</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Rótulo</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Endereço</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Falha na exportação</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Ocorreu um erro ao tentar salvar o histórico de transações em %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Exportação feita com êxito</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>O histórico de transação foi gravado com êxito em %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Intervalo: </translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>para</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1725,6 +2935,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Nenhuma carteira carregada</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <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 da guia atual para um arquivo</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Backup da carteira</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Dados da carteira (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Falha no backup</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Ocorreu um erro ao tentar salvar os dados da carteira em %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Êxito no backup</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Os dados da carteira foram salvos com êxito em %1.</translation>
+ </message>
+</context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1747,24 +3006,32 @@
<translation>Aceitar linha de comando e comandos JSON-RPC</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>Aceitar conecções de entrada (padrão: 1 sem -proxy ou -connect/-noconnect)</translation>
+ </message>
+ <message>
+ <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
+ <translation>Conectar somente a nós específicos; -noconnect ou -connect=0 sozinhos para desativar conecções automáticas</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>Distribuído sob a MIT software license, veja o arquivo %s ou %s</translation>
+ </message>
+ <message>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation>Se &lt;category&gt; não for suprida ou se &lt;category&gt; = 1, mostrar toda informação de depuração.</translation>
</message>
<message>
<source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
- <translation>Corte configurado abaixo do nível mínimo de %d de MiB. Por favor use um número mais alto.</translation>
+ <translation>Prune configurado abaixo do mínimo de %d MiB. Por favor use um número mais alto.</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>Corte: a ultima sincronização da carteira foi além do dado comprimido. Você precisa reindexar ( -reindex , faça 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 os requerimentos de armazenamento de dados (cortando) deletando 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 = desabilita o corte de blocos, &gt;%u = tamanho alvo em MiB para o uso de blocos cortados)</translation>
+ <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>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 de corte. Você precisa usar -reindex, que irá fazer o download de toda a blockchain novamente.</translation>
+ <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>
<message>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
@@ -1787,16 +3054,12 @@
<translation>Não foi possível iniciar o servidor HTTP. Veja o log para detaihes.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Aceitar conexões externas (padrão: 1 se opções -proxy ou -connect não estiverem presentes)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
- <translation>Bitcoin</translation>
+ <translation>Bitcoin Core</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee está muito alta! Essa é a taxa de transação que você vai pagar quando a taxa estimada não estiver disponível.</translation>
+ <source>The %s developers</source>
+ <translation>Desenvolvedores do %s</translation>
</message>
<message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
@@ -1819,10 +3082,6 @@
<translation>Apaga todas as transações da carteira e somente recupera essas partes da blockchain usando o comando -rescan na inicialização</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuido sob a licença MIT software license. Veja os termos em &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
<translation>Erro ao carregar %s. Não é permitido habilitar HD em carteiras não-HD pre existentes.</translation>
</message>
@@ -1835,12 +3094,16 @@
<translation>Executa um comando quando uma transação da carteira mudar (%s no comando será substituído por TxID)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Força a retransmissão de transações de pares da lista branca, mesmo quando violam a política local de retransmissão (default: %d)</translation>
+ <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 mediana 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>
+ <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>
<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>
@@ -1855,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>
@@ -1864,23 +3135,39 @@
</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>Este pode ser um build de teste pré-lançamento - use por sua conta e risco - não use para mineração ou aplicações de comércio.</translation>
+ <translation>Este é um build de teste pré-lançamento - use por sua conta e risco - não use para mineração ou comércio.</translation>
+ </message>
+ <message>
+ <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
+ <translation>Não foi possível reanalisar o banco de dados para o estado pre-fork. Você precisa rebaixar o blockchain</translation>
</message>
<message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<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>
+ <message>
<source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
<translation>Atenção: A rede não parecem concordar plenamente! Alguns mineiros parecem estar enfrentando 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>Atenção: Nós não parecemos concordar plenamente com nossos colegas! Você pode precisar atualizar ou outros nós podem precisar atualizar.</translation>
+ <translation>Atenção: Nós não parecemos concordar plenamente com nossos nós! Você pode precisar atualizar ou outros nós podem precisar atualizar.</translation>
</message>
<message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Lista Branca pares de ligação da máscara de rede dado ou o endereço IP . Pode ser especificado várias vezes.</translation>
+ <source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
+ <translation>Você precisa reconstruir o banco de dados utilizando -reindex-chainstate para mudar -txindex</translation>
+ </message>
+ <message>
+ <source>%s corrupt, salvage failed</source>
+ <translation>%s corrompido, recuperação falhou</translation>
</message>
<message>
<source>-maxmempool must be at least %d MB</source>
@@ -1903,14 +3190,26 @@
<translation>Opções de criação de blocos:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Conectar apenas a cliente(s) específico(s)</translation>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>Impossível resolver -%s endereço: '%s'</translation>
+ </message>
+ <message>
+ <source>Chain selection options:</source>
+ <translation>Opções da rede:</translation>
+ </message>
+ <message>
+ <source>Change index out of range</source>
+ <translation>Índice de mudança fora da faixa.</translation>
</message>
<message>
<source>Connection options:</source>
<translation>Opções de conexão:</translation>
</message>
<message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Copyright (C) %i-%i</translation>
+ </message>
+ <message>
<source>Corrupted block database detected</source>
<translation>Detectado Banco de dados de blocos corrompido</translation>
</message>
@@ -1955,6 +3254,22 @@
<translation>Erro ao inicializar ambiente de banco de dados de carteira %s!</translation>
</message>
<message>
+ <source>Error loading %s</source>
+ <translation>Erro ao carregar %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation>Erro ao carregar %s Carteira corrompida</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation>Erro ao carregar %s A carteira requer a versão mais nova do %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: You can't disable HD on a already existing HD wallet</source>
+ <translation>Erro ao carregar %s: Você não pode desabilitar HD numa já existente carteira HD.</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>Erro ao carregar banco de dados de blocos</translation>
</message>
@@ -1979,10 +3294,18 @@
<translation>Bloco gênese incorreto ou não encontrado. Datadir errado para a rede?</translation>
</message>
<message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation>O teste de integridade de inicialização falhou. O %s está sendo desligado.</translation>
+ </message>
+ <message>
<source>Invalid -onion address: '%s'</source>
<translation>Endereço -onion inválido: '%s'</translation>
</message>
<message>
+ <source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
+ <translation>Valor inválido para -%s=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
<source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
<translation>Valor inválido para -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
@@ -1991,12 +3314,12 @@
<translation>Mantenha a mempool de transações abaixo de &lt;n&gt; megabytes (padrão: %u)</translation>
</message>
<message>
- <source>Location of the auth cookie (default: data dir)</source>
- <translation>Localização do cookie de autenticação (padrão: diretório de dados)</translation>
+ <source>Loading banlist...</source>
+ <translation>Carregando lista de banidos...</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>Número mínimo de bytes por sigop em transações que transmitimos e mineramos (default: %u)</translation>
+ <source>Location of the auth cookie (default: data dir)</source>
+ <translation>Localização do cookie de autenticação (padrão: diretório de dados)</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -2007,16 +3330,32 @@
<translation>Somente conectar a clientes na rede &lt;net&gt; (ipv4, ipv6 ou onion)</translation>
</message>
<message>
+ <source>Print this help message and exit</source>
+ <translation>Mostra essa mensagem de ajuda e sai</translation>
+ </message>
+ <message>
<source>Print version and exit</source>
- <translation>Mostra a versão e sai</translation>
+ <translation>Mostra a versão e fecha</translation>
</message>
<message>
<source>Prune cannot be configured with a negative value.</source>
- <translation>O modo Prune não pode ser configurado com um valor negativo.</translation>
+ <translation>O modo prune não pode ser configurado com um valor negativo.</translation>
</message>
<message>
<source>Prune mode is incompatible with -txindex.</source>
- <translation>O modo Prune é incompatível com -txindex.</translation>
+ <translation>O modo prune é incompatível com -txindex.</translation>
+ </message>
+ <message>
+ <source>Rebuild chain state and block index from the blk*.dat files on disk</source>
+ <translation>Reconstruir índice de cadeia de bloco a partir dos arquivos blk*.dat no disco</translation>
+ </message>
+ <message>
+ <source>Rebuild chain state from the currently indexed blocks</source>
+ <translation>Reconstruir estado a partir dos blocos indexados</translation>
+ </message>
+ <message>
+ <source>Rewinding blocks...</source>
+ <translation>Reanalizando blocos...</translation>
</message>
<message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
@@ -2031,6 +3370,10 @@
<translation>Especifique o arquivo da carteira (dentro do diretório de dados)</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation>O código fonte está disponível pelo %s</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Argumento não suportado -benchmark ignorado, use -debug=bench.</translation>
</message>
@@ -2047,6 +3390,10 @@
<translation>Use UPnP para mapear a porta de entrada (padrão: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Usar a rede de testes</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>Comentário do Agente de Usuário (%s) contém caracteres inseguros.</translation>
</message>
@@ -2063,6 +3410,14 @@
<translation>Carteira %s reside fora do diretório de dados %s</translation>
</message>
<message>
+ <source>Wallet debugging/testing options:</source>
+ <translation>Opções de depuração/teste da Carteira</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>A Carteira precisou ser reescrita: reinicie o %s para completar</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Opções da carteira:</translation>
</message>
@@ -2092,7 +3447,7 @@
</message>
<message>
<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>Executa um comando quando um alerta relevante é recebido ou vemos uma longa segregação (%s em cmd é substituído pela mensagem)</translation>
+ <translation>Executa um comando quando um alerta relevante é recebido ou vemos uma longa segregação (%s é substituída pela mensagem)</translation>
</message>
<message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source>
@@ -2104,17 +3459,13 @@
</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>Valor inválido para -maxtxfee = &lt;valor&gt;: '%s'( precisa ser pelo menos a comissão mínima de %s para prevenir travamento de transações)</translation>
+ <translation>Valor inválido para -maxtxfee=&lt;valor&gt;: '%s' (precisa ser pelo menos a taxa mínima de %s para prevenir que a transação nunca seja confirmada)</translation>
</message>
<message>
<source>Maximum size of data in data carrier transactions we relay and mine (default: %u)</source>
<translation>Tamanho máximo de dados em transações de dados de operadora (padrão %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Buscar por endereços de peers via busca DNS, se estiver baixo em endereços (padrão: 1 a não ser que -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Gerar credenciais aleatórias para cada conexão por proxy. Isto habilita o isolamento de stream do Tor (padrão: %u)</translation>
</message>
@@ -2127,8 +3478,8 @@
<translation>A quantia da transação é muito pequena para mandar </translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Esse produto inclui software desenvolvido pelo Open SSL Project para uso na OpenSSL Toolkit &lt;https://www.openssl.org&gt; e software criptográfico escrito por Eric Young e software UPnP escrito por Thomas Bernard. </translation>
+ <source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
+ <translation>Usar carteira HD. Somente tem efeito na criação de uma nova carteira</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>
@@ -2239,10 +3590,6 @@
<translation>Quantidade da transação muito pequena.</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>As quantidades das transações devem ser positivas.</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transação muito grande para enviar sem taxa</translation>
</message>
@@ -2307,18 +3654,22 @@
<translation>-maxtxfee é muito alto! Essa quantia poderia ser paga em uma única transação.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee é muito alto! Este é o valor da taxa de transação que você irá pagar se enviar a transação.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Não manter transações na mempool por mais que &lt;n&gt; horas (padrão: %u)</translation>
</message>
<message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Número mínimo de bytes por assinatura em transações que transmitimos e mineramos (default: %u)</translation>
+ </message>
+ <message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation>Comissões (em %s/kB) menores serão consideradas como zero para criação de transação (padrão %s)</translation>
</message>
<message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>Força a retransmissão de transações de pares da lista branca, mesmo quando violam a política local de retransmissão (default: %d)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>Quão completa a verificação de blocos do -checkblocks é (0-4, padrão: %u)</translation>
</message>
@@ -2335,10 +3686,26 @@
<translation>Informação de saída de debug (padrão: %u, definir &lt;category&gt; é opcional)</translation>
</message>
<message>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
+ <translation>Buscar por endereços de peers via DNS, se estiver baixo em endereços (padrão: 1 a não ser 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>Define a criação do raw da transação ou bloco em modo não verbal, não segwit (0) ou segwit (1) (padrão: %d)</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation>Suportar filtragem de blocos e transações com filtros 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 que você deve pagar quando a taxa estimada não está disponível.</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>Esse produto inclui um software desenvolvido pelo OpenSSL Project para uso na 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>O tamanho total da string de versão da rede (%i) excede o tamanho máximo (%i). Reduza o numero ou tamanho de uacomments.</translation>
</message>
@@ -2359,14 +3726,22 @@
<translation>Use um proxy SOCKS5 separado para alcançar participantes da rede via serviços ocultos Tor (padrão: %s)</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. This option can be specified multiple times</source>
- <translation>Nome de usuário e senha hash 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. Essa opção pode ser especificada múltiplas vezes.</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>Aviso: Versões de bloco desconhecidas sendo mineradas! É possível que regras estranhas estejam ativas</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>Atenção: Arquivo da carteira corrompido, dados recuperados! Original %s salvo como %s em %s; se seu saldo ou transações estiverem incorretos, você deve restaurar o backup.</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>Lista Branca de conecções do endereço IP informado (ex: 1.2.3.4) ou com máscara de rede (ex: 1.2.3.0/24). Pode ser especificado várias vezes.</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation>%s está muito alto!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(padrão: %s)</translation>
</message>
@@ -2387,6 +3762,10 @@
<translation>Endereço -proxy inválido: '%s'</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Erro na Keypool, favor executar keypoolrefill primeiro</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>Escutar por conexões JSON-RPC na porta &lt;port&gt; (padrão: %u ou testnet: %u)</translation>
</message>
@@ -2423,12 +3802,16 @@
<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>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Definir tamanho mínimo do bloco, em bytes (padrão: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Define a altura máxima BIP141 do bloco (padrão: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
@@ -2444,17 +3827,45 @@
</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>
<translation>Gastar troco não confirmado quando enviar transações (padrão: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Iniciando análise da rede...</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>A carteira irá evitar pagar menos que a taxa mínima.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Esta é a taxa mínima que você deve pagar em cada transação.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Esta é a taxa que você irá pagar se enviar a transação.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Limite para desconectar peers mal comportados (padrão: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>As quantidades das transações devem ser positivas.</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>A transação demorou muito na memória</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>A transação deve ter ao menos um destinatário</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Rede desconhecida especificada em -onlynet: '%s'</translation>
</message>
@@ -2488,7 +3899,7 @@
</message>
<message>
<source>Done loading</source>
- <translation>Carregamento terminado</translation>
+ <translation>Carregamento terminado!</translation>
</message>
<message>
<source>Error</source>
diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts
index eed262e010..c97272d4b7 100644
--- a/src/qt/locale/bitcoin_pt_PT.ts
+++ b/src/qt/locale/bitcoin_pt_PT.ts
@@ -41,24 +41,159 @@
<source>&amp;Delete</source>
<translation>&amp;Eliminar</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Escolha o endereço para enviar as moedas</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Escolha o endereço para receber as moedas</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>Escol&amp;her</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>A enviar endereços</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>A receber endereços</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Copiar Endereço</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copiar &amp;Etiqueta</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Editar</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exportar Lista de Endereços</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Ficheiro separado por vírgulas (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Exportação Falhou</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Ocorreu um erro ao tentar guardar a lista de endereços para %1. Por favor, tente novamente.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Endereço</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sem etiqueta)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
<message>
<source>Passphrase Dialog</source>
- <translation>Janela da frase de palavra-passe</translation>
+ <translation>Janela da Frase de Segurança</translation>
</message>
<message>
<source>Enter passphrase</source>
- <translation>Insira a frase de palavra-passe</translation>
+ <translation>Insira a frase de segurança</translation>
</message>
<message>
<source>New passphrase</source>
- <translation>Nova frase de palavra-passe</translation>
+ <translation>Nova frase de frase de segurança</translation>
</message>
<message>
<source>Repeat new passphrase</source>
- <translation>Repita a nova frase de palavra-passe</translation>
+ <translation>Repita a nova frase de frase de segurança</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>Insira a nova frase de segurança para a carteira. &lt;br/&gt; Por favor, utilize uma frase de segurança de &lt;b&gt;10 ou mais carateres aleatórios,&lt;/b&gt; ou &lt;b&gt;oito ou mais palavras&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Encriptar carteira</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Esta operação precisa da sua frase de segurança da carteira para desbloquear a mesma.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Desbloquear carteira</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Esta operação precisa da sua frase de segurança da carteira para desencriptar a mesma.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Desencriptar carteira</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Alterar frase de segurança</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Insira a frase de segurança antiga e a nova frase de segurança para a carteira.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Confirmar encriptação da carteira</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>Aviso: se encriptar a sua carteira e perder a sua frase de segurnça, &lt;b&gt;PERDERÁ TODOS OS SEUS BITCOINS&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Tem a certeza que deseja encriptar a sua carteira?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Carteira encriptada</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Encriptação da carteira falhou</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>As frases de segurança fornecidas não coincidem.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Desbloqueio da carteira falhou</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Desencriptação da carteira falhou</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>A frase de segurança da carteira foi alterada com sucesso.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Aviso: a tecla Caps Lock está ligada!</translation>
</message>
</context>
<context>
@@ -84,7 +219,7 @@
</message>
<message>
<source>&amp;Overview</source>
- <translation>&amp;Sinopse</translation>
+ <translation>&amp;Resumo</translation>
</message>
<message>
<source>Node</source>
@@ -92,7 +227,7 @@
</message>
<message>
<source>Show general overview of wallet</source>
- <translation>Mostrar sinopse geral da carteira</translation>
+ <translation>Mostrar resumo geral da carteira</translation>
</message>
<message>
<source>&amp;Transactions</source>
@@ -112,19 +247,19 @@
</message>
<message>
<source>&amp;About %1</source>
- <translation>&amp;Acerca de %1</translation>
+ <translation>&amp;Sobre o %1</translation>
</message>
<message>
<source>Show information about %1</source>
- <translation>Mostrar informação sobre %1</translation>
+ <translation>Mostrar informação sobre o %1</translation>
</message>
<message>
<source>About &amp;Qt</source>
- <translation>Sobre &amp;Qt</translation>
+ <translation>Sobre o &amp;Qt</translation>
</message>
<message>
<source>Show information about Qt</source>
- <translation>Mostrar informação sobre Qt</translation>
+ <translation>Mostrar informação sobre o Qt</translation>
</message>
<message>
<source>&amp;Options...</source>
@@ -140,11 +275,11 @@
</message>
<message>
<source>&amp;Backup Wallet...</source>
- <translation>&amp;Guardar Carteira...</translation>
+ <translation>Efetuar &amp;Cópia de Segurança da Carteira...</translation>
</message>
<message>
<source>&amp;Change Passphrase...</source>
- <translation>Alterar &amp;Frase de Palavra-passe...</translation>
+ <translation>Alterar &amp;Frase de Segurança...</translation>
</message>
<message>
<source>&amp;Sending addresses...</source>
@@ -159,12 +294,24 @@
<translation>Abrir &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Clique para desativar a atividade de rede.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Atividade de rede desativada.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Clique para ativar novamente a atividade de rede.</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>A reindexar os blocos no disco...</translation>
</message>
<message>
<source>Send coins to a Bitcoin address</source>
- <translation>Enviar moedas para um endereço bitcoin</translation>
+ <translation>Enviar moedas para um endereço Bitcoin</translation>
</message>
<message>
<source>Backup wallet to another location</source>
@@ -172,11 +319,11 @@
</message>
<message>
<source>Change the passphrase used for wallet encryption</source>
- <translation>Alterar a frase de palavra-passe utilizada na encriptação da carteira</translation>
+ <translation>Alterar a frase de segurança utilizada na encriptação da carteira</translation>
</message>
<message>
<source>&amp;Debug window</source>
- <translation>Janela de &amp;depuração</translation>
+ <translation>Janela de &amp;Depuração</translation>
</message>
<message>
<source>Open debugging and diagnostic console</source>
@@ -216,7 +363,7 @@
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation>Assine mensagens com os seus endereços Bitcoin para provar que os controla</translation>
+ <translation>Assine as mensagens com os seus endereços Bitcoin para provar que é o proprietário dos mesmos</translation>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
@@ -270,34 +417,10 @@
<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>
</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>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n ano</numerusform><numerusform>%n anos</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 em atraso</translation>
@@ -327,6 +450,10 @@
<translation>Atualizado</translation>
</message>
<message>
+ <source>%1 client</source>
+ <translation>Cliente %1</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Recuperando o atraso...</translation>
</message>
@@ -369,6 +496,14 @@
<translation>Transação recebida</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>Criação de chave HD está &lt;b&gt;ativada&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>Criação de chave HD está &lt;b&gt;desativada&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>A carteira está &lt;b&gt;encriptada&lt;/b&gt; e atualmente &lt;b&gt;desbloqueada&lt;/b&gt;</translation>
</message>
@@ -376,7 +511,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -396,10 +531,6 @@
<translation>Valor:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridade:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Taxa:</translation>
</message>
@@ -452,8 +583,72 @@
<translation>Confirmada</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Prioridade</translation>
+ <source>Copy address</source>
+ <translation>Copiar endereço</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar valor</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copiar Id. da transação</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Bloquear não gasto</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Desbloquear não gasto</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copiar quantidade</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copiar taxa</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copiar depois da taxa</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copiar bytes</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copiar troco</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 bloqueado)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>sim</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>não</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sem etiqueta)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>troco de %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(troco)</translation>
</message>
</context>
<context>
@@ -478,12 +673,20 @@
<source>&amp;Address</source>
<translation>E&amp;ndereço</translation>
</message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Não foi possível desbloquear a carteira.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>A criação da nova chave falhou.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
<message>
<source>A new data directory will be created.</source>
- <translation>Irá ser criada uma nova diretoria de dados.</translation>
+ <translation>Será criada uma nova diretoria de dados.</translation>
</message>
<message>
<source>name</source>
@@ -495,7 +698,7 @@
</message>
<message>
<source>Path already exists, and is not a directory.</source>
- <translation>Caminho já existe, e não é uma pasta.</translation>
+ <translation>O caminho já existe, e este não é uma pasta.</translation>
</message>
<message>
<source>Cannot create data directory here.</source>
@@ -514,7 +717,7 @@
</message>
<message>
<source>About %1</source>
- <translation>Sobre %1</translation>
+ <translation>Sobre o %1</translation>
</message>
<message>
<source>Command-line options</source>
@@ -534,11 +737,11 @@
</message>
<message>
<source>Choose data directory on startup (default: %u)</source>
- <translation>Escolha a diretoria dos dados no arranque (predefinição: %u)</translation>
+ <translation>Escolher a pasta de dados no arranque (predefinição: %u)</translation>
</message>
<message>
<source>Set language, for example "de_DE" (default: system locale)</source>
- <translation>Definir linguagem, por exemplo "pt_PT" (por defeito: linguagem do sistema)</translation>
+ <translation>Definir idioma, por exemplo "pt_PT" (predefinição: idioma do sistema)</translation>
</message>
<message>
<source>Start minimized</source>
@@ -546,13 +749,17 @@
</message>
<message>
<source>Set SSL root certificates for payment request (default: -system-)</source>
- <translation>Configurar certificados SSL root para pedido de pagamento (default: -system-)</translation>
+ <translation>Definir certificados de raiz SSL para pedidos de pagamento (predefinição: -system-)</translation>
</message>
<message>
<source>Show splash screen on startup (default: %u)</source>
<translation>Mostrar o ecrã de abertura no arranque (predefinição: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Redefinir todas as definições alteradas na GUI</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -561,19 +768,19 @@
</message>
<message>
<source>Welcome to %1.</source>
- <translation>Bem-vindo a %1.</translation>
+ <translation>Bem-vindo ao %1.</translation>
</message>
<message>
<source>Use the default data directory</source>
- <translation>Utilizar a diretoria de dados predefinida</translation>
+ <translation>Utilizar a pasta de dados predefinida</translation>
</message>
<message>
<source>Use a custom data directory:</source>
- <translation>Utilizar uma diretoria de dados personalizada:</translation>
+ <translation>Utilizar uma pasta de dados personalizada:</translation>
</message>
<message>
<source>Error: Specified data directory "%1" cannot be created.</source>
- <translation>Erro: não pode ser criada a diretoria de dados especificada como "%1.</translation>
+ <translation>Erro: não pode ser criada a pasta de dados especificada como "%1.</translation>
</message>
<message>
<source>Error</source>
@@ -589,6 +796,45 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Número de blocos restantes</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Desconhecido...</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Data do último bloco</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>Progresso</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>a calcular...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>tempo restante estimado até à sincronização</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Ocultar</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Desconhecido. Sincronização de Cabeçalhos (%1)...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -604,7 +850,11 @@
</message>
<message>
<source>Select payment request file</source>
- <translation>Seleccione o ficheiro de pedido de pagamento</translation>
+ <translation>Selecione o ficheiro de pedido de pagamento</translation>
+ </message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Selecione o ficheiro de pedido de pagamento para abrir</translation>
</message>
</context>
<context>
@@ -619,7 +869,7 @@
</message>
<message>
<source>Automatically start %1 after logging in to the system.</source>
- <translation>Começar o %1 automaticamente ao iniciar a sessão no sistema.</translation>
+ <translation>Iniciar automaticamente o %1 depois de iniciar a sessão no sistema.</translation>
</message>
<message>
<source>&amp;Start %1 on system login</source>
@@ -647,7 +897,7 @@
</message>
<message>
<source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
- <translation>Endereço IP do proxy (p.ex. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
+ <translation>Endereço de IP do proxy (exemplo, IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
<source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
@@ -688,15 +938,15 @@
</message>
<message>
<source>Expert</source>
- <translation> Especialistas </translation>
+ <translation> Técnicos</translation>
</message>
<message>
<source>Enable coin &amp;control features</source>
- <translation>Ativar as funcionalidades de controlo de moedas</translation>
+ <translation>Ativar as funcionalidades de &amp;controlo de moedas</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>No caso de desativar o gasto de troco não confirmado, o troco de uma transação não poderá ser utilizado até que essa transação tenha pelo menos uma confirmação. Isto também afeta o cálculo do seu saldo.</translation>
+ <translation>Se desativar o gasto de troco não confirmado, o troco de uma transação não pode ser utilizado até que essa transação tenha pelo menos uma confirmação. Isto também afeta o cálculo do seu saldo.</translation>
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
@@ -763,6 +1013,10 @@
<translation>&amp;Janela</translation>
</message>
<message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>&amp;Ocultar o ícone da bandeja do sistema.</translation>
+ </message>
+ <message>
<source>Hide tray icon</source>
<translation>Ocultar ícone da bandeja</translation>
</message>
@@ -828,7 +1082,7 @@
</message>
<message>
<source>This change would require a client restart.</source>
- <translation>Esta alteração requer um reinício do cliente.</translation>
+ <translation>Esta alteração obrigará a um reinício do cliente.</translation>
</message>
<message>
<source>The supplied proxy address is invalid.</source>
@@ -911,6 +1165,37 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Erro do pedido de pagamento</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Pedido de pagamento rejeitado</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Pedido de pagamento expirado.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>O pedido de pagamento não foi inicializado.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Pedido de pagamento inválido.</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Reembolso de %1</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Erro ao comunicar com %1: %2</translation>
+ </message>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -920,11 +1205,7 @@
<source>Node/Service</source>
<translation>Nó/Serviço</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Tempo de Latência</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -963,7 +1244,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 e %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -1159,14 +1450,6 @@
<translation>Limpar consola</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Desligar Nó</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Banir Nó por</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;hora</translation>
</message>
@@ -1183,10 +1466,6 @@
<translation>1 &amp;ano</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Desbloquear Nó</translation>
- </message>
- <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Bem-vindo à consola RPC da %1.</translation>
</message>
@@ -1317,6 +1596,14 @@
<source>Remove</source>
<translation>Remover</translation>
</message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar valor</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1336,7 +1623,30 @@
<source>&amp;Save Image...</source>
<translation>&amp;Salvar Imagem...</translation>
</message>
-</context>
+ <message>
+ <source>Address</source>
+ <translation>Endereço</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Valor</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sem etiqueta)</translation>
+ </message>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1372,10 +1682,6 @@
<translation>Quantia:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioridade:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Taxa:</translation>
</message>
@@ -1389,7 +1695,7 @@
</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>Se isto estiver ativo, mas o endereço de troco estiver vazio ou for inválido, o troco irá ser enviado para um novo endereço.</translation>
+ <translation>Se isto estiver ativo, mas o endereço de troco estiver vazio ou for inválido, o troco será enviado para um novo endereço gerado.</translation>
</message>
<message>
<source>Custom change address</source>
@@ -1397,7 +1703,7 @@
</message>
<message>
<source>Transaction Fee:</source>
- <translation>Custo da Transação:</translation>
+ <translation>Taxa da transação:</translation>
</message>
<message>
<source>Choose...</source>
@@ -1405,7 +1711,7 @@
</message>
<message>
<source>collapse fee-settings</source>
- <translation>fechar definições-de custos</translation>
+ <translation>ocultar definições de taxa</translation>
</message>
<message>
<source>per kilobyte</source>
@@ -1413,7 +1719,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>Se a taxa fixa for 1000 satoshis e a transação for somente 250 bytes, pagará somente 250 satoshis "por kilobyte" em custos se trasacionar "pelo menos" 1000 satoshis. Transações superiores a um kilobyte são cobradas por kilobyte.</translation>
+ <translation>Se a taxa personalizada estiver definida para 1.000 satoshis e a transação é de apenas 250 bytes, então paga apenas 250 satoshis "por kilobyte" na taxa, enquanto em "total pelo menos" paga 1.000 satoshis. Para transações superiores a um kilobyte ambos pagam por kilobyte.</translation>
</message>
<message>
<source>Hide</source>
@@ -1441,11 +1747,7 @@
</message>
<message>
<source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
- <translation>(Taxa inteligente ainda não foi acionada. Normalmente demora alguns blocos...)</translation>
- </message>
- <message>
- <source>Confirmation time:</source>
- <translation>Tempo de confirmação:</translation>
+ <translation>(A taxa inteligente ainda não foi inicializada. Isto normalmente demora alguns blocos...)</translation>
</message>
<message>
<source>normal</source>
@@ -1487,6 +1789,62 @@
<source>S&amp;end</source>
<translation>E&amp;nviar</translation>
</message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copiar quantidade</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar valor</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copiar taxa</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copiar depois da taxa</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copiar bytes</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copiar troco</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>adicionado como taxa de transação</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>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>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Pedido de pagamento expirado.</translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Pague apenas a taxa obrigatória de %1</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Aviso: endereço de troco desconhecido</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>Confirmar endereço de troco personalizado</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sem etiqueta)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1536,7 +1894,7 @@
</message>
<message>
<source>S&amp;ubtract fee from amount</source>
- <translation>S&amp;ubtrair taxa ao montante</translation>
+ <translation>S&amp;ubtrair a taxa ao montante</translation>
</message>
<message>
<source>Message:</source>
@@ -1566,7 +1924,10 @@
<source>Memo:</source>
<translation>Memorando:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1664,7 +2025,7 @@
<source>Reset all verify message fields</source>
<translation>Repor todos os campos de verificação de mensagem</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1680,12 +2041,69 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Taxa de transação</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Valor</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>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(sem etiqueta)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Copy address</source>
+ <translation>Copiar endereço</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copiar etiqueta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copiar valor</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copiar Id. da transação</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Ficheiro separado por vírgulas (*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Endereço</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Exportação Falhou</translation>
+ </message>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1694,6 +2112,19 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <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>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1728,10 +2159,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>
@@ -1741,7 +2168,7 @@
</message>
<message>
<source>Fee (in %s/kB) to add to transactions you send (default: %s)</source>
- <translation>Taxa (em %s/kB) a adicionar às transacções que envia (padrão: %s)</translation>
+ <translation>Taxa (em %s/kB) para adicionar às transações que envia (predefinição: %s)</translation>
</message>
<message>
<source>Pruning blockstore...</source>
@@ -1756,18 +2183,10 @@
<translation>Não é possível iniciar o servidor HTTP. Verifique o debug.log para detalhes.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Aceitar ligações externas (padrão: 1 sem -proxy ou -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee está definida muito elevada! Esta é a taxa de transação pode poderá pagar quando as estimativas de taxas não estão disponíveis.</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>
@@ -1784,16 +2203,8 @@
<translation>Apague todas as transações da carteira e somente restore aquelas que façam parte do blockchain através de re-scan ao reiniciar o programa</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuido através da licença de software MIT, verifique o ficheiro anexado COPYING ou &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
- <translation>Executar comando quando uma das transações na carteira mudar (no comando, %s é substituído pelo ID da Transação)</translation>
- </message>
- <message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Forçar retransmissão das transações a partir dos pares da lista branca, mesmo que estes violem a política de retransmissão local (predefinição: %d)</translation>
+ <translation>Executar o comando quando uma transação da carteira muda (no comando, %s é substituído pela Id. da Transação)</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>
@@ -1804,26 +2215,10 @@
<translation>A base de dados de blocos contém um bloco que aparenta ser do futuro. Isto pode ser causado por uma data incorrecta definida no seu computador. Reconstrua apenas a base de dados de blocos caso tenha a certeza de que a data e hora do seu computador estão correctos.</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 é uma versão de testes pré-lançamento - use à sua responsabilidade - não usar para minar ou aplicações comerciais</translation>
- </message>
- <message>
<source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<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>Atenção: 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>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Ligações na lista branca conectam desde a seguinte netmask ou endereço IP. Posse ser especificado varias vezes.</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>
@@ -1844,10 +2239,6 @@
<translation>Opções da criação de bloco:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Apenas ligar ao(s) nó(s) especificado(s)</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Opções de ligação:</translation>
</message>
@@ -1952,10 +2343,6 @@
<translation>Localização de cookie de autorização (predefinição: diretoria de dados)</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>Mínimo de bytes por sigop nas transações que nós transmitimos e mine (predefinição: %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>Os descritores de ficheiros disponíveis são insuficientes.</translation>
</message>
@@ -2057,7 +2444,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>Taxas (em %s/kB) abaixo deste valor são consideradas nulas para propagação, mineração e criação de transacções (padrão: %s)</translation>
+ <translation>Taxas (em %s/kB) inferiores a este valor são consideradas nulas para propagação, mineração e criação de transações (predefinição: %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>
@@ -2072,10 +2459,6 @@
<translation>Tamanho máximo dos dados em transacções que incluem dados que propagamos e mineramos (padrão: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Encontrar pares usando DNS lookup, caso o número de endereços seja reduzido (padrão: 1 excepto -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Usar credenciais aleatórias por cada ligação proxy. Permite que o Tor use stream isolation (padrão: %u)</translation>
</message>
@@ -2088,10 +2471,6 @@
<translation>O montante da transacção é demasiado baixo após a dedução da taxa</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Este produto inclui software desenvolvido pelo OpenSSL Project para utilização no OpenSSL Toolkit &lt;https://www.openssl.org/&gt; e software criptográfico escrito por Eric Young e software UPnP escrito por Thomas Bernard.</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>Os pares enviados para a lista branca não podem ser DoS banidos e as suas transações são sempre retransmitidas, mesmo que já estejam no banco de memória, útil, por exemplo, para um acesso</translation>
</message>
@@ -2200,10 +2579,6 @@
<translation>Quantia da transação é muito baixa</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Quantia da transação deverá ser positiva</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transacção demasiado grande para a política de taxas</translation>
</message>
@@ -2249,7 +2624,7 @@
</message>
<message>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
- <translation>Executar comando quando o melhor bloco mudar (no comando, %s é substituído pela hash do bloco)</translation>
+ <translation>Executar o comando quando o melhor bloco muda (no comando, %s é substituído pela hash do bloco)</translation>
</message>
<message>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
@@ -2268,10 +2643,6 @@
<translation>-maxtxfee está definido com um valor muito alto! Taxas desta magnitude podem ser pagas numa única transacção.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee está definido com um valor muito alto! Esta é a taxa que irá pagar se enviar uma transacção.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Não guardar transações no banco de memória por mais de &lt;n&gt; horas (predefinição: %u)</translation>
</message>
@@ -2320,10 +2691,6 @@
<translation>Use um proxy SOCKS5 separado para alcançar pares via serviços ocultos do Tor (padrão: %s)</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. This option can be specified multiple times</source>
- <translation>Username e hash da password para ligações JSON-RPC. O campo &lt;userpw&gt; está no formato: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Um script python está incluido em share/rpcuser. Esta opção pode ser especificada múltiplas vezes.</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>Atenção: Versões desconhecidas de blocos estão a ser mineradas! É possível que regras desconhecias estão a ser efetuadas</translation>
</message>
@@ -2388,10 +2755,6 @@
<translation>Definir tamanho do banco de memória da chave para &lt;n&gt; (predefinição: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Definir tamanho minímo de um bloco em bytes (por defeito: %u)</translation>
- </message>
- <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>Defina o número de processos para servir as chamadas RPC (por defeito: %d)</translation>
</message>
@@ -2409,7 +2772,7 @@
</message>
<message>
<source>Spend unconfirmed change when sending transactions (default: %u)</source>
- <translation>Gastar troco não confirmado ao enviar transacções (padrão: %u)</translation>
+ <translation>Gastar o troco não confirmado quando enviar transações (predefinição: %u)</translation>
</message>
<message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
diff --git a/src/qt/locale/bitcoin_ro.ts b/src/qt/locale/bitcoin_ro.ts
index 270a4ba062..ef87f1056a 100644
--- a/src/qt/locale/bitcoin_ro.ts
+++ b/src/qt/locale/bitcoin_ro.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>Șterge</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,59 +63,653 @@
<source>Repeat new passphrase</source>
<translation>Repetati noua parolă</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
- </context>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Netmask</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Blocat până</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
+ <message>
+ <source>Sign &amp;message...</source>
+ <translation>Semnează &amp;mesajul...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network...</source>
+ <translation>Se sincronizează cu rețeaua</translation>
+ </message>
+ <message>
+ <source>Node</source>
+ <translation>Nod</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation>Arată o prezentare generală a portofelului.</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation>&amp;Tranzacții</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation>Navighează în istoricul tranzacțiilor</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>Părăsește aplicația</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation>Despre &amp;Qt</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>Arată informații despre Qt</translation>
+ </message>
+ <message>
+ <source>&amp;Options...</source>
+ <translation>&amp;Opțiuni...</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet...</source>
+ <translation>&amp;Criptează portofelul...</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet...</source>
+ <translation>&amp;Backup portofel</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>&amp;Schimbă parola...</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;Trimite adresele...</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>&amp;Primește adresele...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>Deschide &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation>Trimite monedele către o adresă Bitcoin</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation>Fă o copie de rezervă a portofelului într-o altă locație</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation>Schimbă parola folosită pentru criptarea portofelului</translation>
+ </message>
+ <message>
+ <source>&amp;Debug window</source>
+ <translation>&amp;Fereastra pentru depanare</translation>
+ </message>
+ <message>
+ <source>Open debugging and diagnostic console</source>
+ <translation>Pornește consola pentru depanare si diagnoză</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message...</source>
+ <translation>&amp;Verifică mesajul...</translation>
+ </message>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Portofel</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation>&amp;Trimite</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation>&amp;Primește</translation>
+ </message>
+ <message>
+ <source>&amp;Show / Hide</source>
+ <translation>&amp;Arată/Ascunde</translation>
+ </message>
+ <message>
+ <source>Show or hide the main Window</source>
+ <translation>Arată sau ascunde fereastra principală</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation>Criptează cheile private care aparțin portofelului tău.</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation>Semnează mesajele cu adresa ta de Bitcoin pentru a face dovada că îți aparțin.</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation>Verifică mesajele cu scopul de a asigura faptul că au fost semnate cu adresa de Bitcoin specificată.</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation>&amp;Fișier</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation>&amp;Setări</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation>&amp;Ajutor</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation>Cerere plată (generează coduri QR și bitcoin: URIs)</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI or payment request</source>
+ <translation>Deschide un bitcoin: URI sau cerere de plată</translation>
+ </message>
+ <message>
+ <source>%1 behind</source>
+ <translation>%1 în urmă</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation>Ultimul bloc primit a fost generat acum %1</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Eroare</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Atenționare</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Informație</translation>
+ </message>
+ <message>
+ <source>Up to date</source>
+ <translation>Actual</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation>Data: %1</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Cantitate: %1</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Tip: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Etichetă: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Adresa: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation>Trimite tranzacția</translation>
+ </message>
+ <message>
+ <source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
+ <translation>Portofelul este &lt;b&gt;criptat&lt;/b&gt; și în prezent &lt;b&gt;deblocat&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>Portofelul este &lt;b&gt;criptat&lt;/b&gt; și în prezent &lt;b&gt;blocat&lt;/b&gt;</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
+ <message>
+ <source>Coin Selection</source>
+ <translation>Selecția monedelor</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation>Cantitatea:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Biți:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Cantitate:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Taxa:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>După taxă:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Schimbă:</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation>Mod arbore</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation>Mod listă</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Cantitate</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation>Primit cu adresa</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation>Confirmări</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Confirmat</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation>Modifică adresa</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation>&amp;Adresa</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
+ <message>
+ <source>name</source>
+ <translation>Nume</translation>
+ </message>
+ <message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation>Directoriul există deja. Adaugă %1 dacă ai intenționat să creezi aici un directoriu nou.</translation>
+ </message>
</context>
<context>
<name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation>versiune</translation>
+ </message>
+ <message>
+ <source>(%1-bit)</source>
+ <translation>(%1-bit)</translation>
+ </message>
+ <message>
+ <source>Start minimized</source>
+ <translation>Pornește minimalizat</translation>
+ </message>
</context>
<context>
<name>Intro</name>
+ <message>
+ <source>Welcome</source>
+ <translation>Bine ai venit!</translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation>Folosește directoriul pentru date din modul implicit.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Eroare</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n GB of free space available</source>
+ <translation><numerusform>%n GB de spațiu liber disponibil</numerusform><numerusform>%n GB de spațiu liber disponibil</numerusform><numerusform>%n GB de spațiu liber disponibil</numerusform></translation>
+ </message>
+ </context>
+<context>
+ <name>ModalOverlay</name>
</context>
<context>
<name>OpenURIDialog</name>
+ <message>
+ <source>Open URI</source>
+ <translation>Deschide URI</translation>
+ </message>
+ <message>
+ <source>URI:</source>
+ <translation>URI:</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
+ <message>
+ <source>Options</source>
+ <translation>Opțiuni</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <translation>MB</translation>
+ </message>
+ <message>
+ <source>Accept connections from outside</source>
+ <translation>Acceptă conexiuni externe</translation>
+ </message>
+ <message>
+ <source>Allow incoming connections</source>
+ <translation>Acceptă conexiunea care sosește</translation>
+ </message>
+ <message>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation>Adresa IP a proxy-ului (ex. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation>&amp;Resetează opțiunile</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation>&amp;Rețea</translation>
+ </message>
+ <message>
+ <source>Expert</source>
+ <translation>Expert</translation>
+ </message>
+ <message>
+ <source>Proxy &amp;IP:</source>
+ <translation>Proxy &amp;IP:</translation>
+ </message>
+ <message>
+ <source>&amp;Port:</source>
+ <translation>&amp;Port:</translation>
+ </message>
+ <message>
+ <source>Port of the proxy (e.g. 9050)</source>
+ <translation>Portul pentru proxy (ex.: 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;Fereastra</translation>
+ </message>
+ <message>
+ <source>&amp;OK</source>
+ <translation>&amp;OK</translation>
+ </message>
+ <message>
+ <source>&amp;Cancel</source>
+ <translation>&amp;Anulează</translation>
+ </message>
+ <message>
+ <source>default</source>
+ <translation>inițial</translation>
+ </message>
+ <message>
+ <source>none</source>
+ <translation>fără</translation>
+ </message>
+ <message>
+ <source>Confirm options reset</source>
+ <translation>Confirmă resetarea opțiunilor</translation>
+ </message>
+ <message>
+ <source>Client restart required to activate changes.</source>
+ <translation>Repornirea clientului este necesară pentru ca schimbările să fie activate</translation>
+ </message>
+ <message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>Clientul va fi oprit. Dorești sa continui?</translation>
+ </message>
+ <message>
+ <source>This change would require a client restart.</source>
+ <translation>Această schimbare necesită repornirea clientului.</translation>
+ </message>
</context>
<context>
<name>OverviewPage</name>
+ <message>
+ <source>Available:</source>
+ <translation>Disponibil:</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation>Total:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation>Tranzacții recente</translation>
+ </message>
+ </context>
+<context>
+ <name>PaymentServer</name>
</context>
<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
+ <message>
+ <source>Amount</source>
+ <translation>Cantitate</translation>
+ </message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 și %2</translation>
+ </message>
</context>
<context>
- <name>RPCConsole</name>
+ <name>QObject::QObject</name>
</context>
<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>Client version</source>
+ <translation>Versiunea clientului</translation>
+ </message>
+ <message>
+ <source>&amp;Information</source>
+ <translation>&amp;Informații</translation>
+ </message>
+ <message>
+ <source>Debug window</source>
+ <translation>Fereastra pentru depanare</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <translation>General</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Rețea</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nume</translation>
+ </message>
+ <message>
+ <source>Number of connections</source>
+ <translation>Numărul de conexiuni</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation>Primit</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation>Trimis</translation>
+ </message>
+ <message>
+ <source>Direction</source>
+ <translation>Direcția</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation>Versiune</translation>
+ </message>
+ <message>
+ <source>Connection Time</source>
+ <translation>Durata conexiunii</translation>
+ </message>
+ <message>
+ <source>&amp;Open</source>
+ <translation>&amp;Deschide</translation>
+ </message>
+ <message>
+ <source>&amp;Console</source>
+ <translation>&amp;Consolă</translation>
+ </message>
+ <message>
+ <source>1 &amp;hour</source>
+ <translation>1 &amp;ore</translation>
+ </message>
+ <message>
+ <source>1 &amp;day</source>
+ <translation>1 &amp;zi</translation>
+ </message>
+ <message>
+ <source>1 &amp;week</source>
+ <translation>1 &amp;săptămână</translation>
+ </message>
+ <message>
+ <source>1 &amp;year</source>
+ <translation>1 &amp;an</translation>
+ </message>
+ <message>
+ <source>%1 B</source>
+ <translation>%1 B</translation>
+ </message>
+ <message>
+ <source>%1 KB</source>
+ <translation>%1 KB</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <translation>%1 MB</translation>
+ </message>
+ <message>
+ <source>%1 GB</source>
+ <translation>%1 GB</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Da</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nu</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation>Necunoscut</translation>
+ </message>
+</context>
+<context>
<name>ReceiveCoinsDialog</name>
+ <message>
+ <source>&amp;Message:</source>
+ <translation>&amp;Mesaj:</translation>
+ </message>
+ <message>
+ <source>Show</source>
+ <translation>Arată</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation>Elimină</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Salvează imaginea...</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
</context>
<context>
<name>SendCoinsDialog</name>
+ <message>
+ <source>Quantity:</source>
+ <translation>Cantitatea:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Biți:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Cantitate:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Taxa:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>După taxă:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Schimbă:</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -125,12 +722,46 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
- <name>bitcoin-core</name>
+ <name>WalletFrame</name>
</context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Bitcoin Core</source>
+ <translation>Bitcoin Core</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Informație</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Atenționare</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Eroare</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts
index 489ed07639..3d3a4b0431 100644
--- a/src/qt/locale/bitcoin_ro_RO.ts
+++ b/src/qt/locale/bitcoin_ro_RO.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Şterge</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Repetaţi noua frază de acces</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -250,34 +253,10 @@
<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>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n oră</numerusform><numerusform>%n ore</numerusform><numerusform>%n ore</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n zi</numerusform><numerusform>%n zile</numerusform><numerusform>%n de zile</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n săptămână</numerusform><numerusform>%n săptămâni</numerusform><numerusform>%n de săptămâni</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 şi %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n an</numerusform><numerusform>%n ani</numerusform><numerusform>%n de ani</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 în urmă</translation>
@@ -356,7 +335,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Portofelul este &lt;b&gt;criptat&lt;/b&gt; iar în momentul de faţă este &lt;b&gt;blocat&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -376,10 +355,6 @@
<translation>Sumă:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritate:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Taxă:</translation>
</message>
@@ -431,11 +406,7 @@
<source>Confirmed</source>
<translation>Confirmat</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioritate</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -458,7 +429,7 @@
<source>&amp;Address</source>
<translation>&amp;Adresă</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -565,6 +536,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Data ultimului bloc</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Ascunde</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -582,7 +568,7 @@
<source>Select payment request file</source>
<translation>Selectaţi fişierul cerere de plată</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -858,6 +844,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -867,11 +856,7 @@
<source>Node/Service</source>
<translation>Nod/Serviciu</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Timp ping</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -910,7 +895,21 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 şi %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Salvează imaginea...</translation>
+ </message>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -1074,10 +1073,6 @@
<translation>Curăţă consola</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Deconectare nod</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;oră</translation>
</message>
@@ -1216,7 +1211,7 @@
<source>Remove</source>
<translation>Înlătură</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1235,7 +1230,14 @@
<source>&amp;Save Image...</source>
<translation>&amp;Salvează imaginea...</translation>
</message>
-</context>
+ <message>
+ <source>Amount</source>
+ <translation>Cantitate</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1271,10 +1273,6 @@
<translation>Sumă:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritate:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Taxă:</translation>
</message>
@@ -1323,10 +1321,6 @@
<translation>Personalizat:</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Timp confirmare:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1366,7 +1360,7 @@
<source>S&amp;end</source>
<translation>Trimit&amp;e</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1429,7 +1423,10 @@
<source>Memo:</source>
<translation>Memo:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1519,7 +1516,7 @@
<source>Reset all verify message fields</source>
<translation>Resetează toate cîmpurile mesajelor semnate</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1535,12 +1532,25 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Amount</source>
+ <translation>Cantitate</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Acest panou arată o descriere detaliată a tranzacţiei</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1549,6 +1559,15 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1575,10 +1594,6 @@
<translation>Rulează în fundal ca un demon şi acceptă comenzi</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Acceptă conexiuni din afară (implicit: 1 dacă nu se foloseşte -proxy sau -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Nucleul Bitcoin</translation>
</message>
@@ -1587,10 +1602,6 @@
<translation>Ataşaţi adresei date şi ascultaţi totdeauna pe ea. Folosiţi notaţia [host]:port pentru IPv6</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuit sub licenţa de programe MIT/X11, vezi fişierul însoţitor COPYING sau &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Execută comanda cînd o tranzacţie a portofelului se schimbă (%s în cmd este înlocuit de TxID)</translation>
</message>
@@ -1599,18 +1610,6 @@
<translation>Setează numărul de thread-uri de verificare a script-urilor (%u la %d, 0 = auto, &lt;0 = lasă atîtea nuclee libere, implicit: %d)</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>Aceasta este o versiune de test preliminară - vă asumaţi riscul folosind-o - nu folosiţi pentru minerit sau aplicaţiile comercianţilor</translation>
- </message>
- <message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Atenţie: Reţeaua nu pare să fie de acord în totalitate! Aparent nişte mineri au probleme.</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>Atenţie: Aparent, nu sîntem de acord cu toţi partenerii noştri! Va trebui să faceţi o actualizare, sau alte noduri necesită actualizare.</translation>
- </message>
- <message>
<source>&lt;category&gt; can be:</source>
<translation>&lt;category&gt; poate fi:</translation>
</message>
@@ -1619,10 +1618,6 @@
<translation>Opţiuni creare bloc:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Conectare doar la nod(urile) specificate</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Opţiuni conexiune:</translation>
</message>
@@ -1731,10 +1726,6 @@
<translation>Setează mărimea pentru tranzacţiile prioritare/taxe mici în octeţi (implicit: %d)</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Acest produs include programe dezvoltate de către Proiectul OpenSSL pentru a fi folosite în OpenSSL Toolkit &lt;https://www.openssl.org/&gt; şi programe criptografice scrise de către Eric Young şi programe UPnP scrise de către Thomas Bernard.</translation>
- </message>
- <message>
<source>(default: %u)</source>
<translation>(implicit: %u)</translation>
</message>
@@ -1803,10 +1794,6 @@
<translation>Suma tranzacţionată este prea mică</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Sumele tranzacţionate trebuie să fie pozitive</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Tranzacţie prea mare pentru politică gratis</translation>
</message>
@@ -1863,10 +1850,6 @@
<translation>Adresa -proxy nevalidă: '%s'</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Setare mărime minimă bloc în octeţi (implicit: %u)</translation>
- </message>
- <message>
<source>Specify configuration file (default: %s)</source>
<translation>Specificaţi fişierul configuraţie (implicit: %s)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts
index 60f5d5dfa2..b5f40fc058 100644
--- a/src/qt/locale/bitcoin_ru.ts
+++ b/src/qt/locale/bitcoin_ru.ts
@@ -41,6 +41,77 @@
<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>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>
+ <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>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>Повторите новый пароль</translation>
</message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>Введите новый пароль бумажника.&lt;br/&gt;Используйте пароль, состоящий из &lt;b&gt;десяти или более случайных символов&lt;/b&gt;, или &lt;b&gt;восьми или более слов&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>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>
@@ -159,6 +318,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>
@@ -270,34 +441,10 @@
<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>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n час</numerusform><numerusform>%n часа</numerusform><numerusform>%n часов</numerusform><numerusform>%n часов</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n день</numerusform><numerusform>%n дня</numerusform><numerusform>%n дней</numerusform><numerusform>%n дней</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n неделю</numerusform><numerusform>%n недели</numerusform><numerusform>%n недель</numerusform><numerusform>%n недель</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 и %2</translation>
- </message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n год</numerusform><numerusform>%n лет</numerusform><numerusform>%n лет</numerusform><numerusform>%n года</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 позади</translation>
@@ -327,10 +474,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>
@@ -373,6 +528,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>
@@ -380,6 +543,10 @@
<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>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Произошла неисправимая ошибка. Bitcoin не может безопасно продолжать работу и будет закрыт.</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -400,10 +567,6 @@
<translation>Сумма:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Приоритет:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Комиссия:</translation>
</message>
@@ -456,8 +619,84 @@
<translation>Подтверждено</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Приоритет</translation>
+ <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>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>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>сдача с %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(сдача)</translation>
</message>
</context>
<context>
@@ -482,6 +721,38 @@
<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>
+ <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>
@@ -605,6 +876,57 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <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>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Неизвестно. Синхронизация заголовков (%1)...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -622,6 +944,10 @@
<source>Select payment request file</source>
<translation>Выбрать файл запроса платежа</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Выберите файл запроса платежа</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -655,7 +981,7 @@
</message>
<message>
<source>Accept connections from outside</source>
- <translation>Разрешать соединения извне</translation>
+ <translation>Принимать входящие соединения</translation>
</message>
<message>
<source>Allow incoming connections</source>
@@ -934,6 +1260,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <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>Обработка URI</translation>
+ </message>
+ <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! Это может быть связано с неверным адресом Bitcoin или неправильными параметрами 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>
<source>User Agent</source>
@@ -944,8 +1361,12 @@
<translation>Узел/сервис</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Время задержки</translation>
+ <source>NodeId</source>
+ <translation>Id узла</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Пинг</translation>
</message>
</context>
<context>
@@ -986,6 +1407,72 @@
<source>%1 ms</source>
<translation>%1 мс</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n секунда</numerusform><numerusform>%n секунды</numerusform><numerusform>%n секунд</numerusform><numerusform>%n секунд</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n минута</numerusform><numerusform>%n минут</numerusform><numerusform>%n минут</numerusform><numerusform>%n минут</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n час</numerusform><numerusform>%n часа</numerusform><numerusform>%n часов</numerusform><numerusform>%n часов</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n день</numerusform><numerusform>%n дня</numerusform><numerusform>%n дней</numerusform><numerusform>%n дней</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n неделя</numerusform><numerusform>%n недели</numerusform><numerusform>%n недель</numerusform><numerusform>%n недель</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 и %2</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n год</numerusform><numerusform>%n года</numerusform><numerusform>%n лет</numerusform><numerusform>%n лет</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 ещё не завершился безопасно...</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <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>
+ <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>
@@ -1146,6 +1633,10 @@
<translation>Время задержки</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Мин. пинг</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Смещение времени</translation>
</message>
@@ -1190,14 +1681,6 @@
<translation>Очистить консоль</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Отключить узел</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Заблокировать узел на</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;час</translation>
</message>
@@ -1214,8 +1697,16 @@
<translation>1 &amp;год</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Разблокировать узел</translation>
+ <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>
@@ -1230,6 +1721,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>
@@ -1348,6 +1847,22 @@
<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>
@@ -1367,6 +1882,73 @@
<source>&amp;Save Image...</source>
<translation>&amp;Сохранить изображение...</translation>
</message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Запросить платёж на %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Информация платежа</translation>
+ </message>
+ <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>
+ <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>
+ <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>
@@ -1403,10 +1985,6 @@
<translation>Сумма:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Приоритет:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Комиссия:</translation>
</message>
@@ -1475,10 +2053,6 @@
<translation>(Умная комиссия пока не инициализирована. Обычно для этого требуется несколько блоков...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Время подтверждения:</translation>
- </message>
- <message>
<source>normal</source>
<translation>обычный</translation>
</message>
@@ -1503,6 +2077,10 @@
<translation>Пыль:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Время подтверждения:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Очистить &amp;всё</translation>
</message>
@@ -1518,6 +2096,126 @@
<source>S&amp;end</source>
<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>%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><numerusform>%n блока</numerusform><numerusform>%n блоков</numerusform><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><numerusform>Начало подтверждения ожидается через %n блока.</numerusform><numerusform>Начало подтверждения ожидается через %n блоков.</numerusform><numerusform>Начало подтверждения ожидается через %n блоков.</numerusform></translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Внимание: неверный адрес Bitcoin</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>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1597,6 +2295,17 @@
<source>Memo:</source>
<translation>Примечание:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Введите метку для данного адреса, чтобы добавить его в адресную книгу</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Да</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1695,6 +2404,58 @@
<source>Reset all verify message fields</source>
<translation>Сбросить все поля проверки сообщения</translation>
</message>
+ <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>
@@ -1711,11 +2472,460 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Открыто для ещё %n блока</numerusform><numerusform>Открыто для ещё %n блоков</numerusform><numerusform>Открыто для ещё %n блоков</numerusform><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><numerusform>, разослано через %n узла</numerusform><numerusform>, разослано через %n узлов</numerusform><numerusform>, разослано через %n узлов</numerusform></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 numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>будет доступно через %n блок</numerusform><numerusform>будет доступно через %n блока</numerusform><numerusform>будет доступно через %n блоков</numerusform><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>
+ <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 numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Открыто для ещё %n блока</numerusform><numerusform>Открыто для ещё %n блоков</numerusform><numerusform>Открыто для ещё %n блоков</numerusform><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>Подтверждается (%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>watch-only</source>
+ <translation>только наблюдение</translation>
+ </message>
+ <message>
+ <source>(n/a)</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>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>Определяемое пользователем намерение/цель транзакции.</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>Копировать исходный код транзакции</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>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Экспорт не удался</translation>
+ </message>
+ <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>
@@ -1725,6 +2935,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Не был загружен ни один бумажник.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Отправка</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <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>
<source>Options:</source>
@@ -1747,6 +3006,18 @@
<translation>Принимать командную строку и команды JSON-RPC</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>Принимать подключения снаружи (по умолчанию: 1, если не -proxy или -connect/-disconnect)</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; не предоставлена или равна 1, выводить всю отладочную информацию.</translation>
</message>
@@ -1759,10 +3030,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>
@@ -1787,10 +3054,6 @@
<translation>Невозможно запустить HTTP сервер. Смотри debug лог для подробностей.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Принимать подключения извне (по умолчанию: 1, если не используется -proxy или -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1799,8 +3062,8 @@
<translation>Разработчики %s</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>Установлено очень большое значение -fallbackfee! Это комиссия за транзацию, которую вы можете заплатить, если оценка размера комиссии не доступна. </translation>
+ <source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
+ <translation>Принимать транзакции пересылаемые от узлов из белого списка даже если они не удовлетворяют требованиям ретрансляции (по умолчанию: %d)</translation>
</message>
<message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
@@ -1815,8 +3078,8 @@
<translation>Удалить все транзакции бумажника с возможностью восстановить эти части цепи блоков с помощью -rescan при запуске</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Распространяется под лицензией MIT, см. приложенный файл COPYING или &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
+ <source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
+ <translation>Ошибка загрузки %s: Вы не можете включить HD в уже существующем не-HD кошельке</translation>
</message>
<message>
<source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
@@ -1827,14 +3090,22 @@
<translation>Выполнить команду, когда меняется транзакция в бумажнике (%s в команде заменяется на TxID)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Всегда разрешать транзакции, полученные от участников из белого списка (по умолчанию: %d)</translation>
+ <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>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>
</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>
<translation>Пожалуйста убедитесь в корректности установки времени и даты на вашем компьютере! Если время установлено неверно, %s не будет работать правильно.</translation>
</message>
<message>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</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>
@@ -1847,20 +3118,32 @@
<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>
+ <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>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. Эта опция может быть указана несколько раз</translation>
+ </message>
+ <message>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation>Бумажник не будет создавать транзакции, которые нарушают лимиты цепочки пула в памяти (по умолчанию: %u)</translation>
+ </message>
+ <message>
<source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Внимание: похоже, в сети нет полного согласия! Некоторый майнеры, возможно, испытывают проблемы.</translation>
+ <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>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Вносить в белый список участников, подключающихся с указанной маски сети или IP. Можно использовать многократно.</translation>
+ <source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
+ <translation>Вам необходимо пересобрать базы данных с помощью -reindex-chainstate, чтобы изменить -txindex</translation>
</message>
<message>
<source>%s corrupt, salvage failed</source>
@@ -1887,8 +3170,16 @@
<translation>Параметры создания блоков:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Подключаться только к указанному узлу(ам)</translation>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <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>
@@ -1931,6 +3222,10 @@
<translation>Включить публичную сырую транзакцию в &lt;address&gt;</translation>
</message>
<message>
+ <source>Enable transaction replacement in the memory pool (default: %u)</source>
+ <translation>Включить замену транзакций в пуле памяти (по умолчанию:%u)</translation>
+ </message>
+ <message>
<source>Error initializing block database</source>
<translation>Ошибка инициализации БД блоков</translation>
</message>
@@ -1951,6 +3246,10 @@
<translation>Ошибка загрузки %s: Для бумажника требуется более новая версия %s</translation>
</message>
<message>
+ <source>Error loading %s: You can't disable HD on a already existing HD wallet</source>
+ <translation>Ошибка загрузки %s: Вы не можете включить HD в уже существующем не-HD кошельке</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>Ошибка чтения базы данных блоков</translation>
</message>
@@ -1975,6 +3274,10 @@
<translation>Неверный или отсутствующий начальный блок. Неправильный каталог данных для сети?</translation>
</message>
<message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation>Начальная проверка исправности не удалась. %s завершает работу.</translation>
+ </message>
+ <message>
<source>Invalid -onion address: '%s'</source>
<translation>Неверный -onion адрес: '%s'</translation>
</message>
@@ -1983,6 +3286,10 @@
<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>Keep the transaction memory pool below &lt;n&gt; megabytes (default: %u)</source>
<translation>Сбрасывать транзакции из памяти на диск каждые &lt;n&gt; мегабайт (по умолчанию: %u)</translation>
</message>
@@ -2019,16 +3326,20 @@
<translation>Режим удаления блоков несовместим с -txindex.</translation>
</message>
<message>
+ <source>Rebuild chain state and block index from the blk*.dat files on disk</source>
+ <translation>Перестроить состояние цепи блоков и индекс блоков из blk*.dat файлов с диска</translation>
+ </message>
+ <message>
<source>Rebuild chain state from the currently indexed blocks</source>
<translation>Перестроить индекс цепи из текущих индексированных блоков</translation>
</message>
<message>
- <source>Set database cache size in megabytes (%d to %d, default: %d)</source>
- <translation>Установить размер кэша БД в мегабайтах(от %d до %d, по умолчанию: %d)</translation>
+ <source>Rewinding blocks...</source>
+ <translation>Перемотка блоков...</translation>
</message>
<message>
- <source>Set maximum block cost (default: %d)</source>
- <translation>Задать максимальную стоимость блока (по умолчанию: %d)</translation>
+ <source>Set database cache size in megabytes (%d to %d, default: %d)</source>
+ <translation>Установить размер кэша БД в мегабайтах(от %d до %d, по умолчанию: %d)</translation>
</message>
<message>
<source>Set maximum block size in bytes (default: %d)</source>
@@ -2063,6 +3374,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>
@@ -2135,10 +3450,6 @@
<translation>Наибольший размер данных в носителе данных транзакций, которые мы передаем и генерируем (по умолчанию: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Запрашивать адреса участников с помощью DNS, если адресов мало (по умолчанию: 1, если не указан -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Использовать случайные учётные данные для каждого прокси-подключения. Эта функция позволяет изолировать потоки Tor (по умолчанию: %u)</translation>
</message>
@@ -2151,8 +3462,8 @@
<translation>Сумма транзакции за вычетом комиссии слишком мала</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Этот продукт включает ПО, разработанное OpenSSL Project для использования в OpenSSL Toolkit &lt;https://www.openssl.org/&gt; и криптографическое ПО, написанное Eric Young и ПО для работы с UPnP, написанное Thomas Bernard.</translation>
+ <source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
+ <translation>Использовать иерархическую детерминированную генерацию ключей (HD) после BIP32. Применяется в процессе создания бумажника / первого запуска</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>
@@ -2263,10 +3574,6 @@
<translation>Сумма транзакции слишком мала</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Сумма транзакции должна быть положительна</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Транзакция слишком большая для правил комиссии.</translation>
</message>
@@ -2331,18 +3638,22 @@
<translation>Установлено очень большое значение -maxtxfee. Такие большие комиссии могут быть уплачены в отдельной транзакции.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>Установлено очень большое значение -paytxfee. Такие большие комиссии могут быть уплачены в отдельной транзакции.</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>
</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/Кб) меньшие этого значения считаются нулевыми при создании транзакций (по умолчанию: %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>
@@ -2359,10 +3670,26 @@
<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, если адресов мало (по умолчанию: 1, если не указан -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>Задаёт сериализацию сырой транзакции или хекса блока, возвращённого в не подробном режиме, non-segwit(0) или segwit(1) (по умолчанию: %d)</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<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 и ПО для работы с UPnP, написанное 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>Текущая длина строки версии сети (%i) превышает максимальную длину (%i). Увеливается количество или размер uacomments.</translation>
</message>
@@ -2375,12 +3702,12 @@
<translation>Обнаружен не поддерживаемый аргумент -socks. Выбор версии SOCKS более невозможен, поддерживаются только прокси SOCKS5.</translation>
</message>
<message>
- <source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)</source>
- <translation>Использовать отдельный прокси SOCKS5 для соединения с участниками через скрытые сервисы Tor (по умолчанию: %s)</translation>
+ <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
+ <translation>Не поддерживаемый аргумент -whitelistalwaysrelay игнорируется, используйте -whitelistrelay и/или -whitelistforcerelay.</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. 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". Эта опция может быть указана несколько раз</translation>
+ <source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)</source>
+ <translation>Использовать отдельный прокси SOCKS5 для соединения с участниками через скрытые сервисы Tor (по умолчанию: %s)</translation>
</message>
<message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
@@ -2391,6 +3718,14 @@
<translation>Внимание: Файл бумажника поврежден, данные восстановлены! Оригинальный %s сохранен как %s в %s; Если баланс или транзакции некорректны, вы должны восстановить файл из резервной копии.</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>Вносить в белый список участников, подключающихся с указанного 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>
@@ -2411,6 +3746,10 @@
<translation>Неверный адрес -proxy: '%s'</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Пул ключей опустел, пожалуйста, выполните keypoolrefill</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>Прослушивать подключения JSON-RPC на &lt;порту&gt; (по умолчанию: %u или %u в тестовой сети)</translation>
</message>
@@ -2447,12 +3786,16 @@
<translation>Транслировать не-P2SH мультиподпись (по умолчанию: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>Отправлять транзакции с включенным full-RBF (по умолчанию: %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 minimum block size in bytes (default: %u)</source>
- <translation>Задать минимальный размер блока в байтах (по умолчанию: %u)</translation>
+ <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>
@@ -2475,10 +3818,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_ru_RU.ts b/src/qt/locale/bitcoin_ru_RU.ts
index 66419728e2..60d98c41d9 100644
--- a/src/qt/locale/bitcoin_ru_RU.ts
+++ b/src/qt/locale/bitcoin_ru_RU.ts
@@ -23,7 +23,7 @@
</message>
<message>
<source>C&amp;lose</source>
- <translation>Закрыть</translation>
+ <translation>&amp;Закрыть</translation>
</message>
<message>
<source>Delete the currently selected address from the list</source>
@@ -41,20 +41,27 @@
<source>&amp;Delete</source>
<translation>Удалить</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
<source>Repeat new passphrase</source>
<translation>Повторите новый пароль</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
<context>
<name>BitcoinGUI</name>
<message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin Core</translation>
+ </message>
+ <message>
<source>&amp;Command-line options</source>
<translation>Опции командной строки</translation>
</message>
@@ -119,6 +126,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -136,12 +146,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>&amp;Information</source>
@@ -155,12 +174,18 @@
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -173,18 +198,44 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>Экспортировать</translation>
+ </message>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</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>bitcoin-core</translation>
+ </message>
+ <message>
<source>Information</source>
<translation>Информация</translation>
</message>
@@ -193,6 +244,10 @@
<translation>Предупреждение</translation>
</message>
<message>
+ <source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
+ <translation>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Ошибка</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts
index a4f0ebcb4e..87dc620f0e 100644
--- a/src/qt/locale/bitcoin_sk.ts
+++ b/src/qt/locale/bitcoin_sk.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Kliknutím pravým tlačidlom upravte adresu alebo popis</translation>
+ <translation>Kliknutím pravým tlačidlom upraviť adresu alebo popis</translation>
</message>
<message>
<source>Create a new address</source>
@@ -11,11 +11,11 @@
</message>
<message>
<source>&amp;New</source>
- <translation>&amp;Nové</translation>
+ <translation>&amp;Nový</translation>
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation>Kopírovať práve zvolenú adresu do systémového klipbordu</translation>
+ <translation>Zkopírovať práve zvolenú adresu</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -41,6 +41,13 @@
<source>&amp;Delete</source>
<translation>&amp;Zmazať</translation>
</message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(bez popisu)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,7 +67,7 @@
<source>Repeat new passphrase</source>
<translation>Zopakujte nové heslo</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -115,6 +122,10 @@
<translation>&amp;O %1</translation>
</message>
<message>
+ <source>Show information about %1</source>
+ <translation>Ukázať informácie o %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>O &amp;Qt</translation>
</message>
@@ -127,6 +138,10 @@
<translation>&amp;Možnosti...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Upraviť nastavenia pre %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Zašifrovať Peňaženku...</translation>
</message>
@@ -255,32 +270,16 @@
<translation><numerusform>%n aktívne pripojenie do siete Bitcoin</numerusform><numerusform>%n aktívne pripojenia do siete Bitcoin</numerusform><numerusform>%n aktívnych pripojení do siete Bitcoin</numerusform></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>
- </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>
+ <source>Indexing blocks on disk...</source>
+ <translation>Indexujem bloky na disku...</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation> %1 a %2</translation>
+ <source>Processing blocks on disk...</source>
+ <translation>Spracovávam bloky na disku...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n rok</numerusform><numerusform>%n roky</numerusform><numerusform>%n rokov</numerusform></translation>
+ <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>
</message>
<message>
<source>%1 behind</source>
@@ -311,6 +310,14 @@
<translation>Aktualizovaný</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Ukáž %1 zoznam možných nastavení Bitcoinu pomocou príkazového riadku</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>%1 klient</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Sťahujem...</translation>
</message>
@@ -360,7 +367,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -380,10 +387,6 @@
<translation>Suma:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorita:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Poplatok:</translation>
</message>
@@ -436,10 +439,10 @@
<translation>Potvrdené</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Priorita</translation>
+ <source>(no label)</source>
+ <translation>(bez popisu)</translation>
</message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -462,7 +465,7 @@
<source>&amp;Address</source>
<translation>&amp;Adresa</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -497,6 +500,10 @@
<translation>(%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>O %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Voľby príkazového riadku</translation>
</message>
@@ -532,7 +539,11 @@
<source>Show splash screen on startup (default: %u)</source>
<translation>Zobraziť uvítaciu obrazovku pri štarte (predvolené: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Zrušiť všetky zmeny v GUI</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -540,6 +551,18 @@
<translation>Vitajte</translation>
</message>
<message>
+ <source>Welcome to %1.</source>
+ <translation>Vitajte v %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>Keďže toto je prvé spustenie programu, môžete si vybrať, kam %1 bude ukladať vaše údaje.</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>%1 stiahne a uloží kópiu Bitcoin block chain. Minimálne %2GB dát bude uložených v tejto zložke, a bude sa zväčšovať postupom času. Peňaženka bude taktiež uložená v tejto zložke.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Použiť predvolený dátový adresár</translation>
</message>
@@ -565,6 +588,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Čas posledného bloku</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Skryť</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -582,7 +620,7 @@
<source>Select payment request file</source>
<translation>Vyberte súbor s výzvou k platbe</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -594,6 +632,14 @@
<translation>&amp;Hlavné</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>Automaticky spustiť %1 pri spustení systému.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>&amp;Spustiť %1 pri prihlásení</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>Veľkosť vyrovnávacej pamäti &amp;databázy</translation>
</message>
@@ -730,6 +776,14 @@
<translation>&amp;Okno</translation>
</message>
<message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>&amp;Skryť ikonu zo systémovej lišty.</translation>
+ </message>
+ <message>
+ <source>Hide tray icon</source>
+ <translation>Skryť ikonu v oblasti oznámení</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation>Zobraziť len ikonu na lište po minimalizovaní okna.</translation>
</message>
@@ -750,6 +804,10 @@
<translation>Jazyk užívateľského rozhrania:</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>Jazyk uživateľského rozhrania sa dá nastaviť tu. Toto nastavenie sa uplatní až po reštarte %1.</translation>
+ </message>
+ <message>
<source>&amp;Unit to show amounts in:</source>
<translation>&amp;Zobrazovať hodnoty v jednotkách:</translation>
</message>
@@ -874,6 +932,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -883,11 +944,7 @@
<source>Node/Service</source>
<translation>Uzol/Služba</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Čas odozvy</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -926,7 +983,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation> %1 a %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -954,6 +1021,10 @@
<translation>Používa BerkeleyDB verziu</translation>
</message>
<message>
+ <source>Datadir</source>
+ <translation>Zložka s dátami</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>Čas spustenia</translation>
</message>
@@ -1039,6 +1110,18 @@
<translation>Aplikácia</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>Otvoriť %1 ladiaci výpis z aktuálnej zložky. Pre veľké súbory to môže chvíľu trvať.</translation>
+ </message>
+ <message>
+ <source>Decrease font size</source>
+ <translation>Zmenšiť písmo</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation>Zväčšiť písmo</translation>
+ </message>
+ <message>
<source>Services</source>
<translation>Služby</translation>
</message>
@@ -1063,6 +1146,10 @@
<translation>Čas odozvy</translation>
</message>
<message>
+ <source>The duration of a currently outstanding ping.</source>
+ <translation>Trvanie aktuálneho pingu</translation>
+ </message>
+ <message>
<source>Ping Wait</source>
<translation>Čakanie na ping</translation>
</message>
@@ -1111,14 +1198,6 @@
<translation>Vymazať konzolu</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Odpojené uzly</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Blokovať uzol na</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;hodinu</translation>
</message>
@@ -1135,8 +1214,8 @@
<translation>1 &amp;rok</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;odblokovať uzol</translation>
+ <source>Welcome to the %1 RPC console.</source>
+ <translation>Vitajte v %1 RPC konzole</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>
@@ -1265,7 +1344,7 @@
<source>Remove</source>
<translation>Odstrániť</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1284,7 +1363,14 @@
<source>&amp;Save Image...</source>
<translation>Uložiť obrázok...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(bez popisu)</translation>
+ </message>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1320,10 +1406,6 @@
<translation>Suma:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Priorita:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Poplatok:</translation>
</message>
@@ -1392,10 +1474,6 @@
<translation>(Automatický poplatok ešte nebol aktivovaný. Toto zvyčajne trvá niekoľko blokov...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Čas potvrdenia:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normálne</translation>
</message>
@@ -1435,6 +1513,14 @@
<source>S&amp;end</source>
<translation>&amp;Odoslať</translation>
</message>
+ <message>
+ <source>or</source>
+ <translation>alebo</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(bez popisu)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1514,10 +1600,17 @@
<source>Memo:</source>
<translation>Poznámka:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down...</source>
+ <translation>%1 sa vypína...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation>Nevypínajte počítač kým toto okno nezmizne.</translation>
</message>
@@ -1600,7 +1693,7 @@
<source>Reset all verify message fields</source>
<translation>Obnoviť všetky polia v overiť správu</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1616,12 +1709,25 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </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>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(bez popisu)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1630,6 +1736,15 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1652,6 +1767,14 @@
<translation>Prijímať príkazy z príkazového riadku a JSON-RPC</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>
+ <message>
+ <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
+ <translation>Redukcia nastavená pod minimálnu hodnotu %d MiB. Prosím použite vyššiu hodnotu.</translation>
+ </message>
+ <message>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
<translation>Chyba: Vyskytla sa interná chyba, pre viac informácií zobrazte debug.log</translation>
</message>
@@ -1672,50 +1795,52 @@
<translation>Nepodarilo sa spustiť HTTP server. Pre viac detailov zobrazte debug log.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Prijať spojenia zvonku (predvolené: 1 ak žiadne -proxy alebo -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Jadro Bitcoin</translation>
</message>
<message>
+ <source>The %s developers</source>
+ <translation>Vývojári %s</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>
<message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation>Nemožné uzamknúť zložku %s. %s pravdepodobne už beží.</translation>
+ </message>
+ <message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation>Vymazať všetky transakcie z peňaženky a pri spustení znova získať z reťazca blokov iba tie získané pomocou -rescan</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuované pod softvérovou licenciou MIT, viď sprievodný súbor COPYING alebo &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
+ <source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
+ <translation>Chyba počas načítavania %s: Nemôžete povoliť HD na už existujúcej non-HD peaženke</translation>
</message>
<message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Vykonaj príkaz keď sa zmení transakcia peňaženky (%s v príkaze je nahradená TxID)</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>Nastaviť počeť vlákien overujúcich skripty (%u až %d, 0 = auto, &lt;0 = nechať toľkoto jadier voľných, prednastavené: %d)</translation>
+ <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
+ <translation>Prosím skontrolujte systémový čas a dátum. Keď je váš čas nesprávny, %s nebude fungovať 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 pred-testovacia verzia - použitie je na vlastné riziko - nepoužívajte na tvorbu bitcoin ani obchodovanie.</translation>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
+ <translation>Keď si myslíte, že %s je užitočný, podporte nás. Pre viac informácií o software navštívte %s.</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.
-
-The network does not appear to fully agree! Some miners appear to be experiencing issues.</translation>
+ <source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
+ <translation>Nastaviť počeť vlákien overujúcich skripty (%u až %d, 0 = auto, &lt;0 = nechať toľkoto jadier voľných, prednastavené: %d)</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>
+ <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>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>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Uzle na zoznam povolených, ktoré sa pripájajú z danej netmask alebo IP adresy. Môže byť zadané viac krát.</translation>
+ <source>%s corrupt, salvage failed</source>
+ <translation>%s je poškodený, záchrana zlyhala</translation>
</message>
<message>
<source>-maxmempool must be at least %d MB</source>
@@ -1730,14 +1855,18 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Voľby vytvorenia bloku:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Pripojiť sa len k určenej nóde</translation>
+ <source>Change index out of range</source>
+ <translation>Menný index mimo rozsah</translation>
</message>
<message>
<source>Connection options:</source>
<translation>Možnosti pripojenia:</translation>
</message>
<message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Copyright (C) %i-%i</translation>
+ </message>
+ <message>
<source>Corrupted block database detected</source>
<translation>Zistená poškodená databáza blokov</translation>
</message>
@@ -1766,6 +1895,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Povoliť zverejnenie raw bloku pre &lt;address&gt;</translation>
</message>
<message>
+ <source>Enable publish raw transaction in &lt;address&gt;</source>
+ <translation>Povoliť publikovať hrubý prevod v &lt;address&gt;</translation>
+ </message>
+ <message>
<source>Error initializing block database</source>
<translation>Chyba inicializácie databázy blokov</translation>
</message>
@@ -1810,6 +1943,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Nesprávny alebo žiadny genesis blok nájdený. Nesprávny dátový priečinok alebo sieť?</translation>
</message>
<message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation>Kontrola čistoty pri inicializácií zlyhala. %s sa vypína.</translation>
+ </message>
+ <message>
<source>Invalid -onion address: '%s'</source>
<translation>Neplatná -onion adresa: '%s'</translation>
</message>
@@ -1826,6 +1963,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Načítavam banlist...</translation>
</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>
+ </message>
+ <message>
<source>Not enough file descriptors available.</source>
<translation>Nedostatok kľúčových slov súboru.</translation>
</message>
@@ -1834,6 +1975,14 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Pripojiť iba k uzlom v sieti &lt;net&gt; (ipv4, ipv6, alebo onion)</translation>
</message>
<message>
+ <source>Print this help message and exit</source>
+ <translation>Vytlačiť túto pomocnú správu a ukončiť</translation>
+ </message>
+ <message>
+ <source>Print version and exit</source>
+ <translation>Vytlačiť verziu a ukončiť</translation>
+ </message>
+ <message>
<source>Prune cannot be configured with a negative value.</source>
<translation>Redukovanie nemôže byť nastavené na zápornú hodnotu.</translation>
</message>
@@ -1842,6 +1991,14 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Redukovanie je nekompatibilné s -txindex.</translation>
</message>
<message>
+ <source>Rebuild chain state and block index from the blk*.dat files on disk</source>
+ <translation>Obnoviť stav reťazca a index blokov zo súborov blk*.dat na disku.</translation>
+ </message>
+ <message>
+ <source>Rebuild chain state from the currently indexed blocks</source>
+ <translation>Obnoviť stav reťazca z aktuálne indexovaných blokov.</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>Nastaviť veľkosť pomocnej pamäti databázy v megabajtoch (%d do %d, prednastavené: %d)</translation>
</message>
@@ -1854,6 +2011,14 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Označ súbor peňaženky (v priečinku s dátami)</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation>Zdrojový kód je dostupný z %s</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation>Nemožné pripojiť k %s na tomto počíťači. %s už pravdepodobne beží.</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Nepodporovaný parameter -benchmark bol ignorovaný, použite -debug=bench.</translation>
</message>
@@ -1882,6 +2047,14 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Peňaženka %s sa nachádza mimo dátového priečinka %s </translation>
</message>
<message>
+ <source>Wallet debugging/testing options:</source>
+ <translation>Ladiace / testovacie možnosti peňaženky.</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>Peňaženka musí byť prepísaná: pre dokončenie reštartujte %s</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Voľby peňaženky:</translation>
</message>
@@ -1926,10 +2099,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Maximálna veľkosť dát v transakciách nosných dát, ktoré prenášame a ťažíme (predvolené: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Dotaz na partnerské adresy pomocou vyhľadávania DNS v prípade nedostatku adries (predvolené: 1, pokiaľ -connect)</translation>
- </message>
- <message>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
<translation>Nastaviť najväčšiu veľkosť vysoká-dôležitosť/nízke-poplatky transakcií v bajtoch (prednastavené: %d)</translation>
</message>
@@ -1938,10 +2107,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Suma je príliš malá pre odoslanie tranzakcie</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Tento produkt obsahuje softvér vyvinutý projektom OpenSSL pre použitie sady nástrojov OpenSSL &lt;https://www.openssl.org/&gt; a kryptografického softvéru napísaného Eric Young a UPnP softvér napísaný Thomas Bernard.</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>Uzle na zoznam povolených nemôžu byť DoS zakázané a ich transakcie vždy postúpené ďalej, aj v prípade, ak sú už pamäťovej fronte. Užitočné napr. pre brány</translation>
</message>
@@ -1998,6 +2163,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Možnosti servra RPC:</translation>
</message>
<message>
+ <source>Rescan the block chain for missing wallet transactions on startup</source>
+ <translation>Pri spustení skontrolovať reťaz blokov pre chýbajúce transakcie peňaženky</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Odoslať trace/debug informácie na konzolu namiesto debug.info žurnálu</translation>
</message>
@@ -2034,10 +2203,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Suma transakcie príliš malá</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Hodnoty transakcie musia byť väčšie ako nula (pozitívne)</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transakcia je príliš veľká pre aktuálne podmienky poplatkov</translation>
</message>
@@ -2066,6 +2231,10 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Zmazať všetky transakcie z peňaženky...</translation>
</message>
<message>
+ <source>ZeroMQ notification options:</source>
+ <translation>Možnosti pripojenia ZeroMQ:</translation>
+ </message>
+ <message>
<source>Password for JSON-RPC connections</source>
<translation>Heslo pre JSON-rPC spojenia</translation>
</message>
@@ -2102,10 +2271,34 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Výstupné ladiace informácie (predvolené: %u, dodanie &lt;category&gt; je voliteľné)</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>
+ <message>
+ <source>Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)</source>
+ <translation>Sa snaží držať odchádzajúce prevádzku v rámci daného cieľa (v MB za 24h), 0 = žiadny limit (predvolený: %d)</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source>
+ <translation>Nepodporovaný argument -socks nájdený. Nastavenie SOCKS verzie už nie je viac moźné, iba SOCKS5 proxies sú podporované.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
+ <translation>Nepodporovaný argument -whitelistalwaysrelay ignorovaný, použite -whitelistrelay a/alebo -whitelistforcerelay.</translation>
+ </message>
+ <message>
<source>Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)</source>
<translation>Použiť samostatný SOCKS5 proxy server na dosiahnutie počítačov cez skryté služby Tor (predvolené: %s)</translation>
</message>
<message>
+ <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
+ <translation>Varovanie: Neznáma verzia blokov sa doluje! Je možné, že neznáme pravidlá majú efekt</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>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>(default: %s)</source>
<translation>(predvolené: %s)</translation>
</message>
@@ -2162,10 +2355,6 @@ The network does not appear to fully agree! Some miners appear to be experiencin
<translation>Nastaviť veľkosť kľúča fronty na &lt;n&gt; (predvolené: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Nastaviť minimálnu veľkosť bloku v bajtoch (predvolené: %u)</translation>
- </message>
- <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>Nastaviť počet vlákien na obsluhu RPC volaní (predvolené: %d)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts
index 16ef20ea3a..8a21f978ef 100644
--- a/src/qt/locale/bitcoin_sl_SI.ts
+++ b/src/qt/locale/bitcoin_sl_SI.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>I&amp;zbriši</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,10 +63,18 @@
<source>Repeat new passphrase</source>
<translation>Ponovite novo geslo</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
- </context>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Netmaska</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Prepoved do</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
@@ -243,32 +254,16 @@
<translation><numerusform>%n aktivna povezava v omrežje Bitcoin</numerusform><numerusform>%n aktivni povezavi v omrežje Bitcoin</numerusform><numerusform>%n aktivne povezave v omrežje Bitcoin</numerusform><numerusform>%n aktivnih povezav v omrežje Bitcoin</numerusform></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>
- </message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n uro</numerusform><numerusform>%n uri</numerusform><numerusform>%n ure</numerusform><numerusform>%n ur</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n dan</numerusform><numerusform>%n dneva</numerusform><numerusform>%n dni</numerusform><numerusform>%n dni</numerusform></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n teden</numerusform><numerusform>%n tedna</numerusform><numerusform>%n tedne</numerusform><numerusform>%n tednov</numerusform></translation>
+ <source>Indexing blocks on disk...</source>
+ <translation>Indeksirani bloki na disku ...</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 in %2</translation>
+ <source>Processing blocks on disk...</source>
+ <translation>Obdelava blokov na disku ...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n leto</numerusform><numerusform>%n leti</numerusform><numerusform>%n leta</numerusform><numerusform>%n let</numerusform></translation>
+ <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>
</message>
<message>
<source>%1 behind</source>
@@ -299,6 +294,10 @@
<translation>Posodobljeno</translation>
</message>
<message>
+ <source>%1 client</source>
+ <translation>%1 odjemalec</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Dohitevam omrežje ...</translation>
</message>
@@ -348,7 +347,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Denarnica je &lt;b&gt;šifrirana&lt;/b&gt; in trenutno &lt;b&gt;zaklenjena&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -368,10 +367,6 @@
<translation>Znesek:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioriteta:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Provizija:</translation>
</message>
@@ -423,11 +418,7 @@
<source>Confirmed</source>
<translation>Potrjeno</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Prioriteta</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -450,7 +441,7 @@
<source>&amp;Address</source>
<translation>&amp;Naslov</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -485,6 +476,10 @@
<translation>(%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>O %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Možnosti ukazne vrstice</translation>
</message>
@@ -496,6 +491,18 @@
<source>command-line options</source>
<translation>možnosti ukazne vrstice</translation>
</message>
+ <message>
+ <source>UI Options:</source>
+ <translation>UI možnosti:</translation>
+ </message>
+ <message>
+ <source>Set language, for example "de_DE" (default: system locale)</source>
+ <translation>Nastavi jezik, na primer "sl_SI" (privzeto: sistemsko)</translation>
+ </message>
+ <message>
+ <source>Start minimized</source>
+ <translation>Začni minimizirano</translation>
+ </message>
</context>
<context>
<name>Intro</name>
@@ -504,6 +511,10 @@
<translation>Dobrodošli</translation>
</message>
<message>
+ <source>Welcome to %1.</source>
+ <translation>Dobrodošli v %1</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Uporabi privzeto podatkovno mapo</translation>
</message>
@@ -529,6 +540,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Oblika</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Čas zadnjega bloka</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Skrij</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -546,7 +572,7 @@
<source>Select payment request file</source>
<translation>Izbiranje datoteke z zahtevkom za plačilo</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -814,6 +840,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -823,11 +852,7 @@
<source>Node/Service</source>
<translation>Naslov</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Odzivni čas</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -866,7 +891,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 in %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -1136,7 +1171,7 @@
<source>Remove</source>
<translation>Odstrani</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1155,7 +1190,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Shrani sliko ...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1191,10 +1229,6 @@
<translation>Znesek:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioriteta:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Provizija:</translation>
</message>
@@ -1263,10 +1297,6 @@
<translation>(Samodejni obračun provizije še ni pripravljen. Po navadi izračun traja nekaj blokov ...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Čas do potrditve:</translation>
- </message>
- <message>
<source>normal</source>
<translation>navadno</translation>
</message>
@@ -1306,7 +1336,7 @@
<source>S&amp;end</source>
<translation>&amp;Pošlji</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1385,7 +1415,10 @@
<source>Memo:</source>
<translation>Opomba:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1479,7 +1512,7 @@
<source>Reset all verify message fields</source>
<translation>Počisti vsa polja za vnos v oknu za preverjanje</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1495,12 +1528,21 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>V tem podoknu so prikazane podrobnosti o transakciji</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1509,6 +1551,19 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Izvozi podatke v trenutnem zavihku v datoteko</translation>
+ </message>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1535,10 +1590,6 @@
<translation>Teci v ozadju in sprejemaj ukaze</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Sprejemaj zunanje povezave (privzeto: 1, razen če ste vklopili opciji -proxy ali -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1547,10 +1598,6 @@
<translation>Veži dani naslov in tam vedno poslušaj. Za naslove protokola IPv6 uporabite zapis [gostitelj]:vrata.</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuirano v okviru programske licence MIT. Podrobnosti so navedene v priloženi datoteki COPYING ali na naslovu &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Izvedi ukaz, ko bo transakcija denarnice se spremenila (V cmd je bil TxID zamenjan za %s)</translation>
</message>
@@ -1559,22 +1606,6 @@
<translation>Nastavi število niti za preverjanje skript (%u do %d, 0 = samodejno, &lt;0 toliko procesorskih jeder naj ostane prostih, privzeto: %d)</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>To je preizkusna različica še neizdanega programa. Uporabljate jo na lastno odgovornost. Programa ne uporabljajte je za rudarjenje ali trgovske aplikacije.</translation>
- </message>
- <message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Opozorilo: Trenutno na omrežju ni videti konsenza! Videti je, kot da bi imeli nekateri rudarji težave.</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>Opozorilo: Trenutno se s soležniki ne strinjam v popolnosti! Mogoče bi morali vi ali drugi udeleženci posodobiti odjemalce.</translation>
- </message>
- <message>
- <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Sprejemaj povezave samo od soležnikov, ki so na naslovih, ki ustrezajo navedeni omrežni maski ali naslovu. Opcijo lahko navedete večkrat.</translation>
- </message>
- <message>
<source>&lt;category&gt; can be:</source>
<translation>&lt;category&gt; je lahko:</translation>
</message>
@@ -1583,10 +1614,6 @@
<translation>Možnosti ustvarjanja blokov:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Poveži se samo z (enim ali več) navedenimi vozlišči</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Izbire povezave:</translation>
</message>
@@ -1763,10 +1790,6 @@
<translation>Znesek je pramajhen</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Znesek mora biti pozitiven</translation>
- </message>
- <message>
<source>Transaction too large</source>
<translation>Transkacija je prevelika</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sq.ts b/src/qt/locale/bitcoin_sq.ts
index 6c86b7d9fc..8baddf6912 100644
--- a/src/qt/locale/bitcoin_sq.ts
+++ b/src/qt/locale/bitcoin_sq.ts
@@ -33,6 +33,69 @@
<source>&amp;Delete</source>
<translation>&amp;Fshi</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Zgjidh adresen ku do te dergoni monedhat</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Duke derguar adresen</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Duke marr adresen</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>Këto janë Bitcoin adresat e juaja për të dërguar pagesa. Gjithmon kontrolloni shumën dhe adresën pranuese para se të dërgoni monedha.</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>Këto janë Bitcoin adresat e juaja për të pranuar pagesa. Rekomandohet që gjithmon të përdorni një adresë të re për çdo transaksion.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopjo adresen</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopjo &amp;Etiketë</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Ndrysho</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Eksporto listën e adresave</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Skedar i ndarë me pikëpresje(*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksportimi dështoj</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Gabim gjatë ruajtjes së listës së adresave në %1. Ju lutem provoni prapë.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiketë</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresë</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(pa etiketë)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -48,7 +111,67 @@
<source>Repeat new passphrase</source>
<translation>Përsërisni frazkalimin e ri</translation>
</message>
-</context>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Kripto portofolin</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Ky veprim ka nevojë per frazkalimin e portofolit tuaj që të ç'kyç portofolin.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>ç'kyç portofolin.</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Ky veprim kërkon frazkalimin e portofolit tuaj që të dekriptoj portofolin.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dekripto portofolin</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Ndrysho frazkalimin</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Konfirmoni enkriptimin e portofolit</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Jeni te sigurt te enkriptoni portofolin tuaj?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Portofoli u enkriptua</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Enkriptimi i portofolit dështoi</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Enkriptimi i portofolit dështoi për shkak të një gabimi të brëndshëm. portofoli juaj nuk u enkriptua.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Frazkalimet e plotësuara nuk përputhen.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>ç'kyçja e portofolit dështoi</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Frazkalimi i futur për dekriptimin e portofolit nuk ishte i saktë.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Dekriptimi i portofolit dështoi</translation>
+ </message>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -127,10 +250,6 @@
<translation>Shiriti i mjeteve</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 dhe %2</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 Pas</translation>
</message>
@@ -166,7 +285,7 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Portofoli po &lt;b&gt; enkriptohet&lt;/b&gt; dhe është &lt;b&gt; i kyçur&lt;/b&gt;</translation>
</message>
-</context>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -185,6 +304,22 @@
<source>Date</source>
<translation>Data</translation>
</message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopjo adresën</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>po</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>jo</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(pa etiketë)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -200,6 +335,34 @@
<source>&amp;Address</source>
<translation>&amp;Adresa</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Adresë e re pritëse</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Adresë e re dërgimi</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Ndrysho adresën pritëse</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>ndrysho adresën dërguese</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Adresa e dhënë "%1" është e zënë në librin e adresave. </translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Nuk mund të ç'kyçet portofoli.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Krijimi i çelësit të ri dështoi.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -227,6 +390,13 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formilarë</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -248,6 +418,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -256,6 +429,16 @@
<source>Amount</source>
<translation>Sasia</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 dhe %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -301,6 +484,33 @@
<source>Copy &amp;Address</source>
<translation>&amp;Kopjo adresen</translation>
</message>
+ <message>
+ <source>Address</source>
+ <translation>Adresë</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Sasia</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiketë</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiketë</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(pa etiketë)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -328,7 +538,19 @@
<source>Confirm the send action</source>
<translation>Konfirmo veprimin e dërgimit</translation>
</message>
- </context>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>konfirmo dërgimin e monedhave</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Shuma e paguar duhet të jetë më e madhe se 0.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(pa etiketë)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -359,6 +581,13 @@
<source>Pay To:</source>
<translation>Paguaj drejt:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Krijoni një etiketë për këtë adresë që t'ja shtoni librit të adresave</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
</context>
<context>
<name>ShutdownWindow</name>
@@ -389,16 +618,166 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Open until %1</source>
+ <translation>Hapur deri më %1</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/I pakonfirmuar</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 konfirmimet</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, nuk është transmetuar me sukses deri tani</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>i/e panjohur</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>transaksionit</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Sasia</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Ky panel tregon një përshkrim të detajuar të transaksionit</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Lloji</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiketë</translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Hapur deri më %1</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>I/E konfirmuar(%1 konfirmime)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Ky bllok është marrë nga ndonjë nyje dhe ka shumë mundësi të mos pranohet! </translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>I krijuar por i papranuar</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Marrë me</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Dërguar drejt</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Pagesë ndaj vetvetes</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minuar</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(p/a)</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(pa etiketë)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Received with</source>
+ <translation>Marrë me</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Dërguar drejt</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minuar</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopjo adresën</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Skedar i ndarë me pikëpresje(*.csv)</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Lloji</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etiketë</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresë</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksportimi dështoj</translation>
+ </message>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Dërgo Monedha</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Eksporto të dhënat e skedës korrente në një skedar</translation>
+ </message>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts
index 6b6f1af6f6..f880dd227e 100644
--- a/src/qt/locale/bitcoin_sr.ts
+++ b/src/qt/locale/bitcoin_sr.ts
@@ -2,6 +2,10 @@
<context>
<name>AddressBookPage</name>
<message>
+ <source>Right-click to edit address or label</source>
+ <translation>Kliknite desnim klikom radi izmene adrese ili oznake</translation>
+ </message>
+ <message>
<source>Create a new address</source>
<translation>Napravite novu adresu</translation>
</message>
@@ -18,14 +22,41 @@
<translation>Kopirajte</translation>
</message>
<message>
+ <source>C&amp;lose</source>
+ <translation>Zatvorite</translation>
+ </message>
+ <message>
<source>Delete the currently selected address from the list</source>
<translation>Izbrisite trenutno izabranu adresu sa liste</translation>
</message>
<message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Eksportuj podatke iz izabrane kartice u fajl</translation>
+ </message>
+ <message>
<source>&amp;Delete</source>
<translation>&amp;Избриши</translation>
</message>
-</context>
+ <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>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -40,7 +71,7 @@
<source>Repeat new passphrase</source>
<translation>Поновите нову лозинку</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -131,6 +162,10 @@
<translation>Трака са картицама</translation>
</message>
<message>
+ <source>Error</source>
+ <translation>Greška</translation>
+ </message>
+ <message>
<source>Up to date</source>
<translation>Ажурно</translation>
</message>
@@ -154,7 +189,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -188,7 +223,7 @@
<source>&amp;Address</source>
<translation>&amp;Адреса</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -205,6 +240,17 @@
</context>
<context>
<name>Intro</name>
+ <message>
+ <source>Error</source>
+ <translation>Greška</translation>
+ </message>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -236,6 +282,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -246,7 +295,21 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </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>
@@ -262,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>
@@ -271,6 +338,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -288,7 +358,7 @@
<source>S&amp;end</source>
<translation>&amp;Пошаљи</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -313,6 +383,13 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Da</translation>
+ </message>
+</context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -337,16 +414,34 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Ovaj odeljak pokazuje detaljan opis transakcije</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -377,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>
@@ -392,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_sr@latin.ts b/src/qt/locale/bitcoin_sr@latin.ts
index 86243bc14c..2cfb95fb21 100644
--- a/src/qt/locale/bitcoin_sr@latin.ts
+++ b/src/qt/locale/bitcoin_sr@latin.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Izbrisati</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,55 @@
<source>Repeat new passphrase</source>
<translation>Ponovo unesite pristupnu frazu</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>Unesite novu pristupnu frazu u novčanik. &lt;br/&gt;Molimo, koristite pristupnu frazu koja ima &lt;b&gt; deset ili više nasumičnih znakova&lt;/b&gt;, ili &lt;b&gt;osam ili više reči&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Šifrujte novčanik</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Da biste otključali novčanik potrebno je da unesete svoju pristupnu frazu.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Otključajte novčanik</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Da biste dešifrovali novčanik, potrebno je da unesete svoju pristupnu frazu.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dešifrujte novčanik</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Promenite pristupnu frazu</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Unesite u novčanik staru pristupnu frazu i novu pristupnu frazu.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Potvrdite šifrovanje novčanika</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>Upozorenje: Ako šifrujete svoj novčanik, i potom izgubite svoju pristupnu frazu &lt;b&gt;IZGUBIĆETE SVE SVOJE BITKOINE&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Da li ste sigurni da želite da šifrujete svoj novčanik?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Novčanik je šifrovan</translation>
+ </message>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -75,13 +126,143 @@
<context>
<name>BitcoinGUI</name>
<message>
+ <source>Synchronizing with network...</source>
+ <translation>Usklađivanje sa mrežom...</translation>
+ </message>
+ <message>
+ <source>&amp;Overview</source>
+ <translation>&amp;Pregled</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>Isključi aplikaciju</translation>
+ </message>
+ <message>
+ <source>&amp;Options...</source>
+ <translation>&amp;Opcije...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>&amp;Izmeni pristupnu frazu...</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;Slanje adresa...</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>&amp;Primanje adresa...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>Otvori &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation>Pošalji novčiće na Bitcoin adresu</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message...</source>
+ <translation>&amp;Proveri poruku...</translation>
+ </message>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Novčanik</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation>&amp;Pošalji</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation>&amp;Primi</translation>
+ </message>
+ <message>
+ <source>&amp;Show / Hide</source>
+ <translation>&amp;Prikazati / Sakriti</translation>
+ </message>
+ <message>
+ <source>Show or hide the main Window</source>
+ <translation>Prikaži ili sakrij glavni prozor</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation>&amp;Podešavanja</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation>&amp;Pomoć</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Greska</translation>
</message>
+ <message>
+ <source>Warning</source>
+ <translation>Upozorenje</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Informacije</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>%1 klijent</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation>Datum: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Iznos: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Tip: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Oznaka: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Adresa: %1
+</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
<message>
+ <source>Quantity:</source>
+ <translation>Količina:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Iznos:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Naknada:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Nakon Naknade:</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation>Kolicina</translation>
</message>
@@ -92,6 +273,18 @@
</context>
<context>
<name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation>Izmeni Adresu</translation>
+ </message>
+ <message>
+ <source>&amp;Label</source>
+ <translation>&amp;Oznaka</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation>&amp;Adresa</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -107,6 +300,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -116,6 +312,9 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -126,6 +325,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -135,12 +340,34 @@
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
+ <message>
+ <source>Quantity:</source>
+ <translation>Količina:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Iznos:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Naknada:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Nakon Naknade:</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -153,18 +380,44 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
+ <source>Information</source>
+ <translation>Informacije</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Upozorenje</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation>Nedovoljno sredstava</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts
index ee46974d8b..2986115a62 100644
--- a/src/qt/locale/bitcoin_sv.ts
+++ b/src/qt/locale/bitcoin_sv.ts
@@ -41,6 +41,78 @@
<source>&amp;Delete</source>
<translation>&amp;Radera</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Välj en adress att sända betalning till</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Välj en adress att ta emot betalning till</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>V&amp;älj</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Avsändaradresser</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Mottagaradresser</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>Detta är dina Bitcoin adresser för att skicka betalningar. Kolla alltid summan och den mottagande adressen innan du skickar Bitcoins.</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>Detta är dina Bitcoin adresser för att ta emot betalningar. Det rekommenderas att använda en ny mottagningsadress för varje transaktion.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopiera adress</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopiera &amp;etikett</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Redigera</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exportera adresslista</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kommaseparerad fil (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Export misslyckades</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Det inträffade ett fel när adresslistan skulle sparas till %1.
+Var vänlig och försök igen.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etikett</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adress</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(Ingen etikett)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -60,6 +132,94 @@
<source>Repeat new passphrase</source>
<translation>Upprepa nytt lösenord</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>Ange plånbokens nya lösenord. &lt;br/&gt; Använd ett lösenord på &lt;b&gt;tio eller fler slumpmässiga tecken,&lt;/b&gt; eller &lt;b&gt;åtta eller fler ord.&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Kryptera plånbok</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Denna operation behöver din plånboks lösenord för att låsa upp plånboken.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Lås upp plånbok</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Denna operation behöver din plånboks lösenord för att dekryptera plånboken.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dekryptera plånbok</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Ändra lösenord</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Ge det gamla lösenordet och det nya lösenordet för plånboken.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Bekräfta kryptering av plånbok</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>VARNING: Om du krypterar din plånbok och glömmer ditt lösenord, kommer du att &lt;b&gt;FÖRLORA ALLA DINA BITCOIN&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Är du säker på att du vill kryptera din plånbok?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Plånbok krypterad</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 kommer nu att stänga ner för att färdigställa krypteringen. Tänk på att en krypterad plånbok inte skyddar mot stöld om din dator är infekterad med en keylogger.</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>VIKTIGT: Alla tidigare säkerhetskopior du har gjort av plånboksfilen ska ersättas med den nya genererade, krypterade plånboksfilen. Av säkerhetsskäl kommer tidigare säkerhetskopior av den okrypterade plånboksfilen blir oanvändbara när du börjar använda en ny, krypterad plånbok.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Kryptering av plånbok misslyckades</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Kryptering av plånbok misslyckades på grund av ett internt fel. Din plånbok blev inte krypterad.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>De angivna lösenorden överensstämmer inte.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Misslyckades låsa upp plånboken</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Lösenordet för dekryptering av plånboken var felaktig.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Dekryptering av plånbok misslyckades</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Plånbokens lösenord har ändrats.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Varning: Caps Lock är påslaget!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -159,6 +319,22 @@
<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>
@@ -270,34 +446,10 @@
<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>
</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>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n år</numerusform><numerusform>%n år</numerusform></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 efter</translation>
@@ -335,6 +487,10 @@
<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>
@@ -384,7 +540,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -404,10 +560,6 @@
<translation>Belopp:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritet:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Avgift:</translation>
</message>
@@ -460,10 +612,34 @@
<translation>Bekräftad</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Prioritet</translation>
+ <source>Copy address</source>
+ <translation>Kopiera adress</translation>
</message>
-</context>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiera etikett</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiera belopp</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopiera transaktions-ID</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>ja</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>nej</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(Ingen etikett)</translation>
+ </message>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -486,7 +662,11 @@
<source>&amp;Address</source>
<translation>&amp;Adress</translation>
</message>
-</context>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Kunde inte låsa upp plånboken.</translation>
+ </message>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -609,6 +789,41 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formulär</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>calculating...</source>
+ <translation>beräknar...</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Göm</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Okänd. Synkar huvuden (%1)...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -626,7 +841,7 @@
<source>Select payment request file</source>
<translation>Välj betalningsbegäransfil</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -938,6 +1153,21 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>URI handling</source>
+ <translation>URI-hantering</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Återbetalning från %1</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Felaktigt svar från server %1</translation>
+ </message>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -948,8 +1178,8 @@
<translation>Nod/Tjänst</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Pingtid</translation>
+ <source>Ping</source>
+ <translation>Ping</translation>
</message>
</context>
<context>
@@ -990,8 +1220,46 @@
<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>
+ <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>
+ <message>
+ <source>Error: %1</source>
+ <translation>Fel: %1</translation>
+ </message>
</context>
<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
<message>
<source>N/A</source>
@@ -1194,14 +1462,6 @@
<translation>Rensa konsollen</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Koppla från nod</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Banna nod i</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;timme</translation>
</message>
@@ -1218,10 +1478,6 @@
<translation>1 &amp;år</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Ta bort ban från nod</translation>
- </message>
- <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Välkommen till %1 RPC-konsolen.</translation>
</message>
@@ -1352,6 +1608,22 @@
<source>Remove</source>
<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>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1371,7 +1643,50 @@
<source>&amp;Save Image...</source>
<translation>&amp;Spara Bild...</translation>
</message>
-</context>
+ <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>Label</source>
+ <translation>Etikett</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Meddelande</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>
+ <message>
+ <source>(no message)</source>
+ <translation>(inget meddelande)</translation>
+ </message>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1407,10 +1722,6 @@
<translation>Belopp:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Prioritet:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Avgift:</translation>
</message>
@@ -1479,10 +1790,6 @@
<translation>(Smartavgiften är inte initierad än. Detta tar vanligen några block...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Bekräftelsetid:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1522,6 +1829,26 @@
<source>S&amp;end</source>
<translation>&amp;Skicka</translation>
</message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiera belopp</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 till %2</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>eller</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n block</numerusform><numerusform>%n block</numerusform></translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(Ingen etikett)</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1601,6 +1928,13 @@
<source>Memo:</source>
<translation>PM:</translation>
</message>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1699,6 +2033,18 @@
<source>Reset all verify message fields</source>
<translation>Rensa alla fält</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>Message verified.</source>
+ <translation>Meddelande verifierat.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1715,12 +2061,81 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Status</source>
+ <translation>Status</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Meddelande</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>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etikett</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(Ingen etikett)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopiera adress</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiera etikett</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiera belopp</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopiera transaktions-ID</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kommaseparerad fil (*.csv)</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etikett</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adress</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Export misslyckades</translation>
+ </message>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1729,6 +2144,15 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1763,10 +2187,6 @@
<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>
@@ -1791,16 +2211,12 @@
<translation>Kunde inte starta HTTP-server. Se avlusningsloggen för detaljer.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Acceptera anslutningar utifrån (förvalt: 1 om ingen -proxy eller -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee är satt väldigt högt! Detta är avgiften du kan komma att betala om uppskattad avgift inte finns tillgänglig.</translation>
+ <source>The %s developers</source>
+ <translation>%s-utvecklarna</translation>
</message>
<message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
@@ -1823,10 +2239,6 @@
<translation>Ta bort alla plånbokstransaktioner och återskapa bara dom som är en del av blockkedjan genom att ange -rescan vid uppstart</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distribuerad under MIT mjukvarulicens, se den bifogade filen COPYING eller &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
<translation>Fel vid laddning av %s: Du kan inte aktivera HD på en existerande icke-HD plånbok</translation>
</message>
@@ -1839,10 +2251,6 @@
<translation>Exekvera kommando när en plånbokstransaktion ändras (%s i cmd är ersatt av TxID)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Vidarebefodra alltid transaktioner från vitlistade noder även om de bryter mot lokala reläpolicyn (förvalt: %d)</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>
@@ -1867,10 +2275,6 @@
<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örhands testbygge - 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>
@@ -1879,18 +2283,6 @@
<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>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>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Vitlista klienter som ansluter från angivna nätmasker eller IP-adresser. Kan specificeras flera gånger.</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>
@@ -1927,10 +2319,6 @@
<translation>Förändringsindexet utom räckhåll</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Koppla enbart upp till den/de specificerade noden/noder</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Anslutningsalternativ:</translation>
</message>
@@ -2051,10 +2439,6 @@
<translation>Plats för authcookie (förvalt: datamapp)</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>Minimum antal byte per sigop i transaktioner som vi reläar och bryter (förvalt: %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>Inte tillräckligt med filbeskrivningar tillgängliga.</translation>
</message>
@@ -2095,10 +2479,6 @@
<translation>Sätt databasens cachestorlek i megabyte (%d till %d, förvalt: %d)</translation>
</message>
<message>
- <source>Set maximum block cost (default: %d)</source>
- <translation>Sätt maximal blockkostnad (förvalt: %d)</translation>
- </message>
- <message>
<source>Set maximum block size in bytes (default: %d)</source>
<translation>Sätt maximal blockstorlek i byte (förvalt: %d)</translation>
</message>
@@ -2203,10 +2583,6 @@
<translation>Maximal storlek på data i databärartransaktioner som vi reläar och bryter (förvalt: %u) </translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Sök efter klientadresser med DNS sökningen, om det finns otillräckligt med adresser (förvalt: 1 om inte -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Slumpa autentiseringen för varje proxyanslutning. Detta möjliggör Tor ström-isolering (förvalt: %u)</translation>
</message>
@@ -2219,10 +2595,6 @@
<translation>Transaktionen är för liten att skicka efter det att avgiften har dragits</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användning i OpenSSL Toolkit &lt;https://www.openssl.org/&gt; och kryptografisk mjukvara utvecklad av Eric Young samt UPnP-mjukvara skriven av Thomas Bernard.</translation>
- </message>
- <message>
<source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
<translation>Använd hierarkisk deterministisk nyckel generering (HD) efter BIP32. Har bara effekt under plånbokens skapande/första användning.</translation>
</message>
@@ -2335,10 +2707,6 @@
<translation>Transaktions belopp för liten</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Transaktionens belopp måste vara positiva</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Transaktionen är för stor för avgiftspolicyn</translation>
</message>
@@ -2403,14 +2771,14 @@
<translation>-maxtxfee är väldigt högt satt! Så höga avgifter kan komma att betalas för en enstaka transaktion.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee är väldigt högt satt! Det här är avgiften du kommer betala om du skickar en transaktion.</translation>
- </message>
- <message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation>Håll inte transaktioner i minnespoolen längre än &lt;n&gt; timmar (förvalt: %u)</translation>
</message>
<message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>Samma antal byte per sigop i transaktioner som vi reläar och bryter (förvalt: %u)</translation>
+ </message>
+ <message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation>Avgifter (i %s/kB) mindre än detta anses vara nollavgifter vid skapande av transaktion (standard: %s)</translation>
</message>
@@ -2455,10 +2823,6 @@
<translation>Använd separat SOCKS5 proxy för att nå kollegor via dolda tjänster i Tor (förvalt: -%s)</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. 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. Detta alternativ kan anges flera gånger</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>Varning: Okända blockversioner bryts! Det är möjligt att okända regler används</translation>
</message>
@@ -2527,8 +2891,8 @@
<translation>Sätt storleken på nyckelpoolen till &lt;n&gt; (förvalt: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Sätt minsta blockstorlek i byte (standard: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Sätt maximal BIP141 blockvikt (förvalt: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
diff --git a/src/qt/locale/bitcoin_ta.ts b/src/qt/locale/bitcoin_ta.ts
index 921171c544..ef8c26c41d 100644
--- a/src/qt/locale/bitcoin_ta.ts
+++ b/src/qt/locale/bitcoin_ta.ts
@@ -25,7 +25,22 @@
<source>&amp;Delete</source>
<translation>&amp;அழி</translation>
</message>
-</context>
+ <message>
+ <source>Sending addresses</source>
+ <translation>முகவரிகள் அனுப்பப்படுகின்றன</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>முகவரிகள் பெறப்படுகின்றன</translation>
+ </message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Address</source>
+ <translation>முகவரி</translation>
+ </message>
+ </context>
<context>
<name>AskPassphraseDialog</name>
</context>
@@ -106,14 +121,6 @@
<source>&amp;Help</source>
<translation>&amp;உதவி</translation>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n மணி</numerusform><numerusform>%n மணி</numerusform></translation>
- </message>
- <message>
- <source>%1 and %2</source>
- <translation>%1 மற்றும் %2</translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 பின்னால்</translation>
@@ -170,10 +177,6 @@
<translation>விலை:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>முன்னுரிமை</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>கட்டணம்:</translation>
</message>
@@ -201,11 +204,7 @@
<source>Confirmed</source>
<translation>உறுதியாக</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>முன்னுரிமை</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
</context>
@@ -231,6 +230,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>படிவம்</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>மறை</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -332,16 +342,15 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
<translation>பயனர் முகவர்</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>பிங் நேரம்</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -368,7 +377,17 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 மற்றும் %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -530,7 +549,7 @@
<source>Remove</source>
<translation>நீக்கு</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -549,7 +568,14 @@
<source>&amp;Save Image...</source>
<translation>&amp;படத்தை சேமி...</translation>
</message>
-</context>
+ <message>
+ <source>Address</source>
+ <translation>முகவரி</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -561,10 +587,6 @@
<translation>விலை</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>முன்னுரிமை</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>கட்டணம்:</translation>
</message>
@@ -600,7 +622,7 @@
<source>S&amp;end</source>
<translation>&amp;அனுப்பு</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -625,6 +647,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -653,12 +678,34 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Address</source>
+ <translation>முகவரி</translation>
+ </message>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Bitcoin Core</source>
diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts
index 34c7526341..ea84d11d39 100644
--- a/src/qt/locale/bitcoin_th_TH.ts
+++ b/src/qt/locale/bitcoin_th_TH.ts
@@ -41,7 +41,22 @@
<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>Sending addresses</source>
+ <translation>ส่งที่อยู่</translation>
+ </message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +75,7 @@
<source>Repeat new passphrase</source>
<translation>กรุณากรอกรหัสผ่านใหม่อีกครั้งหนึ่ง</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -270,34 +285,10 @@
<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>
</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>
<message>
<source>%1 behind</source>
<translation>%1 ตามหลัง</translation>
@@ -384,7 +375,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -404,10 +395,6 @@
<translation>จำนวน:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>ความเร่งด่วน:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>ค่าธรรมเนียม:</translation>
</message>
@@ -459,11 +446,7 @@
<source>Confirmed</source>
<translation>ยืนยันแล้ว</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>ระดับความสำคัญ</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -486,7 +469,7 @@
<source>&amp;Address</source>
<translation>&amp;ที่เก็บ</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -498,6 +481,10 @@
<translation>ชื่อ</translation>
</message>
<message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation>ไดเร็กทอรี่มีอยู่แล้ว ใส่เพิ่ม %1 หากท่านต้องการสร้างไดเร็กทอรี่ใหม่ที่นี่</translation>
+ </message>
+ <message>
<source>Path already exists, and is not a directory.</source>
<translation>พาธ มีอยู่แล้ว พาธนี่ไม่ใช่ไดเร็กทอรี่</translation>
</message>
@@ -605,6 +592,13 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>รูป</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -622,7 +616,7 @@
<source>Select payment request file</source>
<translation>เลือก ไฟล์การเรียกการชำระเงิน</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -798,6 +792,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -806,6 +803,16 @@
<source>Amount</source>
<translation>จำนวน</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 และ %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
</context>
<context>
<name>RPCConsole</name>
@@ -821,6 +828,9 @@
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Send Coins</source>
@@ -839,10 +849,6 @@
<translation>จำนวน:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>ความเร่งด่วน</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>ค่าธรรมเนียม:</translation>
</message>
@@ -867,6 +873,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -883,12 +892,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts
index e3a811b504..2de0d14ddd 100644
--- a/src/qt/locale/bitcoin_tr.ts
+++ b/src/qt/locale/bitcoin_tr.ts
@@ -35,18 +35,89 @@
</message>
<message>
<source>&amp;Export</source>
- <translation>&amp;Dışa aktar</translation>
+ <translation>&amp;Dışarı aktar</translation>
</message>
<message>
<source>&amp;Delete</source>
<translation>&amp;Sil</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Parayı göndermek istediğiniz adresi seçiniz</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Parayı almak istediğiniz adresi seçiniz</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>S&amp;eçiniz</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Gönderilen adresler</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <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;Adresi Kopyala</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>&amp;Etiketi Kopyala</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Değiştir</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <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ı 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>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etiket</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(etiket yok)</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
<message>
<source>Passphrase Dialog</source>
- <translation>Parola diyaloğu</translation>
+ <translation>Parola Diyaloğu</translation>
</message>
<message>
<source>Enter passphrase</source>
@@ -60,27 +131,115 @@
<source>Repeat new passphrase</source>
<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>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>
+ <translation>Cüzdan kilidini kaldır</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <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>
+ <message>
+ <source>Wallet encrypted</source>
+ <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 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>
<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>
@@ -96,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>
@@ -112,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>
@@ -120,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>
@@ -136,15 +295,15 @@
</message>
<message>
<source>&amp;Encrypt Wallet...</source>
- <translation>Cüzdanı &amp;şifrele...</translation>
+ <translation>Cüzdanı &amp;Şifrele...</translation>
</message>
<message>
<source>&amp;Backup Wallet...</source>
- <translation>Cüzdanı &amp;yedekle...</translation>
+ <translation>Cüzdanı &amp;Yedekle...</translation>
</message>
<message>
<source>&amp;Change Passphrase...</source>
- <translation>Parolayı &amp;değiştir...</translation>
+ <translation>Parolayı &amp;Değiştir...</translation>
</message>
<message>
<source>&amp;Sending addresses...</source>
@@ -156,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>
@@ -184,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>
@@ -204,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>
@@ -260,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>
@@ -268,35 +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>
- </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>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n yıl</numerusform><numerusform>%n yıl</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>
@@ -304,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>
@@ -332,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>
@@ -347,7 +502,7 @@
<message>
<source>Amount: %1
</source>
- <translation>Meblağ: %1
+ <translation>Tutar: %1
</translation>
</message>
<message>
@@ -370,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>
@@ -384,6 +547,10 @@
<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>
+ <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>
@@ -401,11 +568,7 @@
</message>
<message>
<source>Amount:</source>
- <translation>Meblağ:</translation>
- </message>
- <message>
- <source>Priority:</source>
- <translation>Öncelik:</translation>
+ <translation>Tutar:</translation>
</message>
<message>
<source>Fee:</source>
@@ -437,7 +600,7 @@
</message>
<message>
<source>Amount</source>
- <translation>Meblağ</translation>
+ <translation>Tutar</translation>
</message>
<message>
<source>Received with label</source>
@@ -460,8 +623,84 @@
<translation>Doğrulandı</translation>
</message>
<message>
- <source>Priority</source>
- <translation>Öncelik</translation>
+ <source>Copy address</source>
+ <translation>Adres kopyala</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Etiket kopyala</translation>
+ </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>
+ <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>
@@ -486,6 +725,38 @@
<source>&amp;Address</source>
<translation>&amp;Adres</translation>
</message>
+ <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>
@@ -499,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>
@@ -581,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>
@@ -609,10 +880,61 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <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>Gizle</translation>
+ </message>
+ <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>
@@ -626,6 +948,10 @@
<source>Select payment request file</source>
<translation>Ödeme talebi dosyasını seç</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Açılacak ödeme talebi dosyasını seç</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -635,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>
@@ -647,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>
@@ -675,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>
@@ -691,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>
@@ -715,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>
@@ -731,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>
@@ -751,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>
@@ -771,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>
@@ -783,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>
@@ -815,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>
@@ -870,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>
@@ -890,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>
@@ -922,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>
@@ -938,6 +1264,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <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>
<source>User Agent</source>
@@ -948,15 +1365,19 @@
<translation>Düğüm/Servis</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Ping Süresi</translation>
+ <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>
@@ -990,6 +1411,72 @@
<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>
+ <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>
+ <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>
+ <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>
@@ -1003,7 +1490,7 @@
</message>
<message>
<source>&amp;Information</source>
- <translation>&amp;Malumat</translation>
+ <translation>&amp;Bilgi</translation>
</message>
<message>
<source>Debug window</source>
@@ -1027,7 +1514,7 @@
</message>
<message>
<source>Network</source>
- <translation>Şebeke</translation>
+ <translation>Ağ</translation>
</message>
<message>
<source>Name</source>
@@ -1051,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>
@@ -1095,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>
@@ -1150,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>
@@ -1167,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>
@@ -1194,14 +1685,6 @@
<translation>Konsolu temizle</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>Düğümle Bağlantıyı &amp;Kes</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Düğümü şu süre için yasakla:</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;saat</translation>
</message>
@@ -1218,8 +1701,16 @@
<translation>1 &amp;yıl</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>Düğümün Yasağını Kald&amp;ır</translation>
+ <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>
@@ -1227,13 +1718,21 @@
</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>
@@ -1286,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>
@@ -1294,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>
@@ -1306,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>
@@ -1318,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>
@@ -1352,6 +1851,22 @@
<source>Remove</source>
<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>Tutarı kopyala</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -1371,6 +1886,73 @@
<source>&amp;Save Image...</source>
<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>
+ <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>
+ <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>
@@ -1404,11 +1986,7 @@
</message>
<message>
<source>Amount:</source>
- <translation>Meblağ:</translation>
- </message>
- <message>
- <source>Priority:</source>
- <translation>Öncelik:</translation>
+ <translation>Tutar:</translation>
</message>
<message>
<source>Fee:</source>
@@ -1432,7 +2010,7 @@
</message>
<message>
<source>Transaction Fee:</source>
- <translation>Muamele ücreti:</translation>
+ <translation>İşlem ücreti:</translation>
</message>
<message>
<source>Choose...</source>
@@ -1448,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>
@@ -1460,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>
@@ -1479,10 +2057,6 @@
<translation>(Zeki ücret henüz başlatılmadı. Bu genelde birkaç blok alır...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Teyit süresi:</translation>
- </message>
- <message>
<source>normal</source>
<translation>normal</translation>
</message>
@@ -1507,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>
@@ -1522,12 +2100,128 @@
<source>S&amp;end</source>
<translation>G&amp;önder</translation>
</message>
+ <message>
+ <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>
</context>
<context>
<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>
@@ -1563,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>
@@ -1591,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>
@@ -1601,6 +2295,17 @@
<source>Memo:</source>
<translation>Not:</translation>
</message>
+ <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>
+ <message>
+ <source>Yes</source>
+ <translation>Evet</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1617,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>
@@ -1649,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>
@@ -1661,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>
@@ -1677,27 +2382,79 @@
</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>
+ <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>
@@ -1715,17 +2472,515 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ <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>
+ <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>
+ <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>
+ <message>
+ <source>Copy label</source>
+ <translation>Etiket kopyala</translation>
+ </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>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>
+ <translation>Etiket</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adres</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Dışarı aktarmada hata</translation>
+ </message>
+ <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>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Hiçbir cüzdan yüklenmedi.</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Bitcoini Gönder</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <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>
@@ -1751,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>
@@ -1776,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>
@@ -1791,10 +3054,6 @@
<translation>HTTP sunucusu başlatılamadı. Ayrıntılar için debug.log dosyasına bakınız.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Dışarıdan gelen bağlantıları kabul et (varsayılan: -proxy veya -connect yoksa 1)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Çekirdeği</translation>
</message>
@@ -1803,16 +3062,12 @@
<translation>%s geliştiricileri</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfee çok yüksek bir değere ayarlanmış! Ücret tahminleri mevcut değilken ödeyebileceğiniz muamele ücretidir bu.</translation>
- </message>
- <message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
<translation>Ücret tahmini için yetersiz veri bulunduğunda kullanılacak ücret oranı (%s/kB olarak) (varsayılan: %s)</translation>
</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>
@@ -1824,11 +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>
- </message>
- <message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>MIT yazılım lisansı kapsamında yayınlanmıştır, ekteki COPYING dosyasına ya da &lt;http://www.opensource.org/licenses/mit-license.php&gt; adresine bakınız.</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>
@@ -1836,23 +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>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>Yerel aktarma politikasını ihlal ettiklerinde bile beyaz listedeki eşlerden gelen muamelelerin aktarılmasını zorla (varsayılan: %d)</translation>
+ <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>
@@ -1863,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>
@@ -1872,7 +3135,7 @@
</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 yayın öncesi bir deneme sürümüdür - tüm riski siz üstlenmiş olursunuz - bitcoin oluşturmak ya da ticari uygulamalar için kullanmayınız</translation>
+ <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>
@@ -1883,16 +3146,20 @@
<translation>Dinlenecek portu haritalamak için UPnP kullan (varsayılan: dinlenildiğinde ve -proxy olmadığında 1)</translation>
</message>
<message>
- <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>Uyarı: şebeke tamamen mutabık değil gibi görünüyor! Bazı madenciler sorun yaşıyor gibi görünüyor.</translation>
+ <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>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ı: eşlerimizle tamamen mutabık değiliz gibi görünüyor! Güncelleme yapmanız gerekebilir ya da diğer düğümlerin güncelleme yapmaları gerekebilir.</translation>
+ <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>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Belirtilen ağ maskesi ya da IP adresinden bağlanan eşleri beyaz listeye al. Birden fazla kez belirtilebilir.</translation>
+ <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>
@@ -1904,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>
@@ -1927,12 +3194,12 @@
<translation>Çözümlenemedi - %s adres: '%s'</translation>
</message>
<message>
- <source>Change index out of range</source>
- <translation>Aralık dışında değişiklik endeksi</translation>
+ <source>Chain selection options:</source>
+ <translation>Blok zinciri seçim ayarları:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Sadece belirtilen düğüme veya düğümlere bağlan</translation>
+ <source>Change index out of range</source>
+ <translation>Aralık dışında değişiklik indeksi</translation>
</message>
<message>
<source>Connection options:</source>
@@ -1964,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>
@@ -1972,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>
@@ -2024,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>
@@ -2036,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>
@@ -2055,16 +3322,12 @@
<translation>auth çerezinin konumu (varsayılan: veri klasörü)</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>Aktardığımız ve oluşturduğumuz muamelelerdeki sigop başına asgari bayt (varsayılan: %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>Kafi derecede dosya tanımlayıcıları mevcut değil.</translation>
</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>
@@ -2084,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>
@@ -2099,12 +3362,8 @@
<translation>Veritabanı önbellek boyutunu megabayt olarak belirt (%d ilâ %d, varsayılan: %d)</translation>
</message>
<message>
- <source>Set maximum block cost (default: %d)</source>
- <translation>Azami blok maliyetini ayarla (varsayılan: %d)</translation>
- </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>
@@ -2135,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>
@@ -2164,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>
@@ -2192,23 +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>
- </message>
- <message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Adres sayısı azaldıysa DNS sorgulamasıyla eş adresleri ara (varsayılan: 1 -connect kullanılmadıysa)</translation>
+ <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>
@@ -2216,15 +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>
- </message>
- <message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Bu ürün OpenSSL projesi tarafından OpenSSL araç takımı (http://www.openssl.org/) için geliştirilen yazılımlar, Eric Young (eay@cryptsoft.com) tarafından hazırlanmış şifreleme yazılımları ve Thomas Bernard tarafından programlanmış UPnP yazılımı içerir.</translation>
+ <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>
@@ -2232,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>
@@ -2276,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>
@@ -2284,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>
@@ -2296,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>
@@ -2316,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>
@@ -2332,27 +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>
- </message>
- <message>
- <source>Transaction amounts must be positive</source>
- <translation>Muamele tutarının pozitif olması lazımdır</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>
@@ -2368,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>
@@ -2404,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>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>-paytxfee çok yüksek bir değere ayarlanmış! Bu, muamele gönderirseniz ödeyeceğiniz muamele ücretidir.</translation>
+ <source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
+ <translation>İşlemleri bellek alanında &lt;n&gt; saatten fazla tutma (varsayılan: %u)</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>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <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>
@@ -2424,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>
@@ -2432,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>
@@ -2459,16 +3730,20 @@
<translation>Eşlere gizli Tor servisleri ile ulaşmak için ayrı SOCKS5 vekil sunucusu kullan (varsayılan: %s)</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. This option can be specified multiple times</source>
- <translation>JSON-RPC bağlantıları için kullanıcı ismi ve karmalanmış parola. &lt;userpw&gt; alanı şu biçimdedir: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Kanonik bir Python betiği share/rpcuser klasöründe bulunabilir. Bu seçenek birden çok kez belirtilebilir.</translation>
- </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>
@@ -2491,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>
@@ -2504,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>
@@ -2520,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 minimum block size in bytes (default: %u)</source>
- <translation>Bayt olarak asgari blok boyutunu tanımla (varsayılan: %u)</translation>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <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>
@@ -2544,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>
@@ -2552,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>
@@ -2572,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>
@@ -2588,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_tr_TR.ts b/src/qt/locale/bitcoin_tr_TR.ts
index 344309c25f..c4e4d2983e 100644
--- a/src/qt/locale/bitcoin_tr_TR.ts
+++ b/src/qt/locale/bitcoin_tr_TR.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Sil</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
</context>
@@ -68,7 +71,7 @@
<source>&amp;Address</source>
<translation>Adres</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -79,6 +82,9 @@
<name>Intro</name>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -88,12 +94,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -107,12 +122,18 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -125,12 +146,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts
index a06cc9e092..2c017fc52e 100644
--- a/src/qt/locale/bitcoin_uk.ts
+++ b/src/qt/locale/bitcoin_uk.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Видалити</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Повторіть пароль</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -254,34 +257,10 @@
<source>%n active connection(s) to Bitcoin network</source>
<translation><numerusform>%n активне з'єднання з мережею Bitcoin</numerusform><numerusform>%n активні з'єднання з мережею Bitcoin</numerusform><numerusform>%n активних з'єднань з мережею Bitcoin</numerusform></translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Недоступно жодного джерела блоків...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Оброблено %n блок історії транзакцій.</numerusform><numerusform>Оброблено %n блоки історії транзакцій.</numerusform><numerusform>Оброблено %n блоків історії транзакцій.</numerusform></translation>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><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></translation>
- </message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><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></translation>
- </message>
<message>
<source>%1 behind</source>
<translation>%1 тому</translation>
@@ -360,7 +339,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -380,10 +359,6 @@
<translation>Сума:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Пріорітет:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Комісія:</translation>
</message>
@@ -435,11 +410,7 @@
<source>Confirmed</source>
<translation>Підтверджені</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Пріоритет</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -462,7 +433,7 @@
<source>&amp;Address</source>
<translation>&amp;Адреса</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -565,6 +536,21 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Час останнього блоку</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Приховати</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -582,7 +568,7 @@
<source>Select payment request file</source>
<translation>Виберіть файл запиту платежу</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -874,6 +860,9 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -883,11 +872,7 @@
<source>Node/Service</source>
<translation>Вузол/Сервіс</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Затримка</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -926,7 +911,17 @@
<source>%1 ms</source>
<translation>%1 мс</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 та %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -1114,14 +1109,6 @@
<translation>Очистити консоль</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>&amp;Від'єднати Вузол</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>Заблокувати Вузол на</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 &amp;годину</translation>
</message>
@@ -1138,10 +1125,6 @@
<translation>1 &amp;рік</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>&amp;Розблокувати Вузол</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>
@@ -1268,7 +1251,7 @@
<source>Remove</source>
<translation>Вилучити</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1287,7 +1270,10 @@
<source>&amp;Save Image...</source>
<translation>&amp;Зберегти зображення...</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1323,10 +1309,6 @@
<translation>Сума:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Пріорітет:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Комісія:</translation>
</message>
@@ -1395,10 +1377,6 @@
<translation>(Розумну оплату ще не ініціалізовано. Це, зазвичай, триває кілька блоків...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Час підтвердження:</translation>
- </message>
- <message>
<source>normal</source>
<translation>звичайний</translation>
</message>
@@ -1438,7 +1416,7 @@
<source>S&amp;end</source>
<translation>&amp;Відправити</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1517,7 +1495,10 @@
<source>Memo:</source>
<translation>Нотатка:</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1611,7 +1592,7 @@
<source>Reset all verify message fields</source>
<translation>Скинути всі поля перевірки повідомлення</translation>
</message>
-</context>
+ </context>
<context>
<name>SplashScreen</name>
<message>
@@ -1627,12 +1608,21 @@
</message>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Даний діалог показує детальну статистику по вибраній транзакції</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1641,6 +1631,15 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
@@ -1675,10 +1674,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>
@@ -1703,10 +1698,6 @@
<translation>Неможливо запустити HTTP-сервер. Детальніший опис наведено в журналі зневадження.</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>Приймати підключення ззовні (типово: 1 за відсутності -proxy чи -connect)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1719,10 +1710,6 @@
<translation>Видалити всі транзакції гаманця та відновити ті, що будуть знайдені під час запуску за допомогою -rescan</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Поширюється за ліцензією MIT, додаткова інформація міститься у файлі COPYING та за адресою &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Виконати команду, коли транзакція гаманця зміниться (замість %s в команді буде підставлено ідентифікатор транзакції)</translation>
</message>
@@ -1735,26 +1722,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>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>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>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>Додати учасників, що під'єднуються з заданої підмережі чи IP-адреси, в білий список. Можна вказувати декілька разів.</translation>
- </message>
- <message>
<source>-maxmempool must be at least %d MB</source>
<translation>-maxmempool має бути не менше %d МБ</translation>
</message>
@@ -1767,10 +1738,6 @@
<translation>Опції створення блоку:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>Підключитись лише до вказаного вузла/вузлів</translation>
- </message>
- <message>
<source>Connection options:</source>
<translation>Параметри з'єднання:</translation>
</message>
@@ -1959,10 +1926,6 @@
<translation>Максимальний розмір даних в транзакціях носіїв даних, що ми передаємо і добуваємо (за замовчуванням: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>Дізнаватися адреси учасників через DNS при замалій кількості відомих адрес (типово: 1 за відсутності -connect)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>Надавати випадкові дані доступу для кожного проксі-з'єднання. Це дозволяє ввімкнути ізоляцію потоків Tor'у (типово: %u)</translation>
</message>
@@ -1975,10 +1938,6 @@
<translation>Залишок від суми транзакції зі сплатою комісії занадто малий </translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>Цей продукт включає в себе програмне забезпечення, розроблене в рамках проекту OpenSSL &lt;https://www.openssl.org/&gt;, криптографічне програмне забезпечення, написане Еріком Янгом, та функції для роботи з UPnP, написані Томасом Бернардом.</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>
</message>
@@ -2087,10 +2046,6 @@
<translation>Сума транзакції занадто мала</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>Суми монет у транзакції мають бути позитивними</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>Транзакція занадто велика для правил комісії</translation>
</message>
@@ -2151,10 +2106,6 @@
<translation>Встановлено дуже велике значення -maxtxfee! Такі великі комісії можуть бути сплачені окремою транзакцією.</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>Встановлено дуже велике значення -paytxfee! Цю комісію буде сплачено для проведення транзакції.</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>
</message>
@@ -2199,10 +2150,6 @@
<translation>Використовувати окремий SOCKS5-проксі для з'єднання з учасниками через приховані сервіси Tor (типово: %s)</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. This option can be specified multiple times</source>
- <translation>Логін та хешований пароль для зв'язків JSON-RPC. Поле &lt;userpw&gt; має формат: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Класичний Python script додано до share/rpcuser. Цей параметр може бути застосований декілька разів.</translation>
- </message>
- <message>
<source>(default: %s)</source>
<translation>(типово: %s)</translation>
</message>
@@ -2263,10 +2210,6 @@
<translation>Встановити розмір пулу ключів &lt;n&gt; (типово: %u)</translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>Встановити мінімальний розмір блоку в байтах (типово: %u)</translation>
- </message>
- <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>Встановити число потоків для обслуговування викликів RPC (типово: %d)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ur_PK.ts b/src/qt/locale/bitcoin_ur_PK.ts
index 6b43bf63e5..923198c91a 100644
--- a/src/qt/locale/bitcoin_ur_PK.ts
+++ b/src/qt/locale/bitcoin_ur_PK.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>مٹا</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -56,7 +59,7 @@
<source>Repeat new passphrase</source>
<translation>نیا پاس فریز دہرائیں</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -92,7 +95,7 @@
<source>&amp;Address</source>
<translation> پتہ</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -107,6 +110,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -116,6 +122,9 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -126,6 +135,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -139,6 +154,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Insufficient funds!</source>
@@ -157,6 +175,9 @@
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -169,12 +190,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Insufficient funds</source>
diff --git a/src/qt/locale/bitcoin_uz@Cyrl.ts b/src/qt/locale/bitcoin_uz@Cyrl.ts
index 0062abfc1d..3898c441af 100644
--- a/src/qt/locale/bitcoin_uz@Cyrl.ts
+++ b/src/qt/locale/bitcoin_uz@Cyrl.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Ўчириш</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>Янги махфий сузни такрорланг</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
</context>
@@ -243,30 +246,6 @@
<translation><numerusform>%n та Bitcoin тармоғига фаол уланиш мавжуд</numerusform></translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Блок манбалари мавжуд эмас...</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>
- <message>
<source>%1 behind</source>
<translation>%1 орқада</translation>
</message>
@@ -314,7 +293,7 @@
<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>
+ </context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -330,10 +309,6 @@
<translation>Миқдори:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Муҳимлиги:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Солиқ:</translation>
</message>
@@ -377,11 +352,7 @@
<source>Confirmed</source>
<translation>Тасдиқланди</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Муҳимлиги</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -404,7 +375,7 @@
<source>&amp;Address</source>
<translation>&amp;Манзил</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -475,6 +446,17 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Шакл</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Сўнгги блок вақти</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -492,7 +474,7 @@
<source>Select payment request file</source>
<translation>Тўлов сўрови файлини танлаш</translation>
</message>
-</context>
+ </context>
<context>
<name>OptionsDialog</name>
<message>
@@ -684,16 +666,15 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
<translation>Фойдаланувчи вакил</translation>
</message>
- <message>
- <source>Ping Time</source>
- <translation>Ping вақти</translation>
- </message>
-</context>
+ </context>
<context>
<name>QObject</name>
<message>
@@ -724,7 +705,17 @@
<source>%1 ms</source>
<translation>%1 мс</translation>
</message>
-</context>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 ва %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
<context>
<name>RPCConsole</name>
<message>
@@ -962,7 +953,7 @@
<source>Remove</source>
<translation>Ўчириш</translation>
</message>
-</context>
+ </context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -977,7 +968,10 @@
<source>&amp;Save Image...</source>
<translation>Расмни &amp;сақлаш</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1009,10 +1003,6 @@
<translation>Миқдори:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Муҳимлиги:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Солиқ:</translation>
</message>
@@ -1049,10 +1039,6 @@
<translation>Тавсия этилган</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>Тасдиқ вақти</translation>
- </message>
- <message>
<source>normal</source>
<translation>Нормал</translation>
</message>
@@ -1088,7 +1074,7 @@
<source>S&amp;end</source>
<translation>Жў&amp;натиш</translation>
</message>
-</context>
+ </context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1133,6 +1119,9 @@
</message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -1173,16 +1162,34 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Ушбу ойна операциянинг батафсил таърифини кўрсатади</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_vi.ts b/src/qt/locale/bitcoin_vi.ts
index e8bf01ab1b..e6775bf205 100644
--- a/src/qt/locale/bitcoin_vi.ts
+++ b/src/qt/locale/bitcoin_vi.ts
@@ -21,7 +21,10 @@
<source>&amp;Delete</source>
<translation>&amp;Xóa</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
</context>
@@ -52,7 +55,7 @@
<source>&amp;Address</source>
<translation>Địa chỉ</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
</context>
@@ -63,6 +66,9 @@
<name>Intro</name>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -72,6 +78,9 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
@@ -82,6 +91,12 @@
</message>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -95,6 +110,9 @@
</message>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Amount:</source>
@@ -105,6 +123,9 @@
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -117,12 +138,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_vi_VN.ts b/src/qt/locale/bitcoin_vi_VN.ts
index a4e1588c93..c27111a52a 100644
--- a/src/qt/locale/bitcoin_vi_VN.ts
+++ b/src/qt/locale/bitcoin_vi_VN.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>&amp;Xó&amp;a</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,13 +63,29 @@
<source>Repeat new passphrase</source>
<translation>Điền lại passphrase</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
- </context>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Netmask</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Bị cấm đến</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
+ <source>Sign &amp;message...</source>
+ <translation>Chứ ký &amp; Tin nhắn...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network...</source>
+ <translation>Đồng bộ hóa với mạng</translation>
+ </message>
+ <message>
<source>&amp;Overview</source>
<translation>&amp;Tổng quan</translation>
</message>
@@ -75,6 +94,18 @@
<translation>Node</translation>
</message>
<message>
+ <source>Show general overview of wallet</source>
+ <translation>Hiện thỉ thông tin sơ lược chung về Ví</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation>&amp;Giao dịch</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation>Duyệt tìm lịch sử giao dịch</translation>
+ </message>
+ <message>
<source>E&amp;xit</source>
<translation>T&amp;hoát</translation>
</message>
@@ -83,6 +114,14 @@
<translation>Thoát chương trình</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>&amp;Thông tin về %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Hiện thông tin về %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>Về &amp;Qt</translation>
</message>
@@ -91,6 +130,30 @@
<translation>Xem thông tin về Qt</translation>
</message>
<message>
+ <source>&amp;Options...</source>
+ <translation>&amp;Tùy chọn...</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation>Chỉnh sửa thiết đặt tùy chọn cho %1</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet...</source>
+ <translation>&amp;Mã hóa ví tiền</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet...</source>
+ <translation>&amp;Sao lưu ví tiền...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>&amp;Thay đổi mật khẩu...</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;Địa chỉ gửi</translation>
+ </message>
+ <message>
<source>&amp;Receiving addresses...</source>
<translation>Địa chỉ nhận</translation>
</message>
@@ -99,6 +162,30 @@
<translation>Mở &amp;URI...</translation>
</message>
<message>
+ <source>Reindexing blocks on disk...</source>
+ <translation>Đánh chỉ số (indexing) lại các khối (blocks) trên ổ đĩa ...</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation>Gửi coins đến tài khoản Bitcoin</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation>Sao lưu ví tiền ở vị trí khác</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation>Thay đổi cụm mật mã dùng cho mã hoá Ví</translation>
+ </message>
+ <message>
+ <source>&amp;Debug window</source>
+ <translation>&amp;Cửa sổ xử lý lỗi (debug)</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message...</source>
+ <translation>&amp;Tin nhắn xác thực</translation>
+ </message>
+ <message>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
@@ -123,6 +210,18 @@
<translation>Hiện hoặc ẩn cửa sổ chính</translation>
</message>
<message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation>Mã hoá các khoá bí mật trong Ví của bạn.</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation>Dùng địa chỉ Bitcoin của bạn ký các tin nhắn để xác minh những nội dung tin nhắn đó là của bạn.</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation>Kiểm tra các tin nhắn để chắc chắn rằng chúng được ký bằng các địa chỉ Bitcoin xác định.</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation>&amp;File</translation>
</message>
@@ -134,25 +233,41 @@
<source>&amp;Help</source>
<translation>Trợ &amp;giúp</translation>
</message>
- <message numerus="yes">
- <source>%n hour(s)</source>
- <translation><numerusform>%n giờ</numerusform></translation>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation>Thanh công cụ (toolbar)</translation>
</message>
- <message numerus="yes">
- <source>%n day(s)</source>
- <translation><numerusform>%n ngày</numerusform></translation>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation>Yêu cầu thanh toán(tạo mã QR và địa chỉ Bitcoin: URLs)</translation>
</message>
- <message numerus="yes">
- <source>%n week(s)</source>
- <translation><numerusform>%n tuần</numerusform></translation>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation>Hiện thỉ danh sách các địa chỉ và nhãn đã dùng để gửi.</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 và %2</translation>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation>Hiện thỉ danh sách các địa chỉ và nhãn đã dùng để nhận.</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI or payment request</source>
+ <translation>Mở bitcoin:URL hoặc yêu cầu thanh toán</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation>7Tùy chọn dòng lệnh</translation>
</message>
- <message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n năm</numerusform></translation>
+ <message>
+ <source>%1 behind</source>
+ <translation>%1 chậm trễ</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation>Khối (block) cuối cùng nhận được cách đây %1</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation>Những giao dịch sau đó sẽ không hiện thị.</translation>
</message>
<message>
<source>Error</source>
@@ -171,6 +286,40 @@
<translation>Đã cập nhật</translation>
</message>
<message>
+ <source>Catching up...</source>
+ <translation>Bắt kịp...</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation>Ngày: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Số lượng: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Loại: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Nhãn hiệu: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Địa chỉ: %1
+</translation>
+ </message>
+ <message>
<source>Sent transaction</source>
<translation>Giao dịch đã gửi</translation>
</message>
@@ -178,6 +327,14 @@
<source>Incoming transaction</source>
<translation>Giao dịch đang tới</translation>
</message>
+ <message>
+ <source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
+ <translation>Ví tiền &lt;b&gt; đã được mã hóa&lt;/b&gt;và hiện &lt;b&gt;đang mở&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>Ví tiền &lt;b&gt; đã được mã hóa&lt;/b&gt;và hiện &lt;b&gt;đang khóa&lt;/b&gt;</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -194,18 +351,30 @@
<translation>Lượng:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Tầm quan trọng:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Phí:</translation>
</message>
<message>
+ <source>After Fee:</source>
+ <translation>Sau thuế, phí:</translation>
+ </message>
+ <message>
<source>Change:</source>
<translation>Thay đổi:</translation>
</message>
<message>
+ <source>(un)select all</source>
+ <translation>(bỏ)chọn tất cả</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation>Chế độ cây</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation>Chế độ danh sách</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation>Lượng</translation>
</message>
@@ -221,14 +390,14 @@
<source>Confirmed</source>
<translation>Đã xác nhận</translation>
</message>
- <message>
- <source>Priority</source>
- <translation>Tầm quan trọng</translation>
- </message>
-</context>
+ </context>
<context>
<name>EditAddressDialog</name>
<message>
+ <source>Edit Address</source>
+ <translation>Thay đổi địa chỉ</translation>
+ </message>
+ <message>
<source>&amp;Label</source>
<translation>Nhãn</translation>
</message>
@@ -236,7 +405,7 @@
<source>&amp;Address</source>
<translation>Địa chỉ</translation>
</message>
-</context>
+ </context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -250,6 +419,30 @@
<source>version</source>
<translation>version</translation>
</message>
+ <message>
+ <source>(%1-bit)</source>
+ <translation>(%1-bit)</translation>
+ </message>
+ <message>
+ <source>Command-line options</source>
+ <translation>&amp;Tùy chọn dòng lệnh</translation>
+ </message>
+ <message>
+ <source>Usage:</source>
+ <translation>Mức sử dụng</translation>
+ </message>
+ <message>
+ <source>command-line options</source>
+ <translation>tùy chọn dòng lệnh</translation>
+ </message>
+ <message>
+ <source>Set language, for example "de_DE" (default: system locale)</source>
+ <translation>Chọn ngôn ngữ, ví dụ "de_DE" (mặc định: Vị trí hệ thống)</translation>
+ </message>
+ <message>
+ <source>Set SSL root certificates for payment request (default: -system-)</source>
+ <translation>Đặt chứng nhận SSL gốc cho yêu cầu giao dịch (mặc định: -hệ thống-)</translation>
+ </message>
</context>
<context>
<name>Intro</name>
@@ -258,11 +451,26 @@
<translation>Chào mừng</translation>
</message>
<message>
+ <source>Use the default data directory</source>
+ <translation>Sử dụng vị trí dữ liệu mặc định</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Lỗi</translation>
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Ẩn</translation>
+ </message>
+ </context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -288,14 +496,58 @@
<translation>MB</translation>
</message>
<message>
+ <source>Accept connections from outside</source>
+ <translation>Chấp nhận các kết nối từ bên ngoài</translation>
+ </message>
+ <message>
+ <source>Allow incoming connections</source>
+ <translation>Cho phép nhận kết nối</translation>
+ </message>
+ <message>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation>Địa chỉ IP của proxy (ví dụ IPv4: 127.0.0.1 / IPv6: ::1)</translation>
+ </message>
+ <message>
+ <source>Third party transaction URLs</source>
+ <translation>Phần mềm giao dịch bên thứ ba URLs</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation>Ví</translation>
</message>
<message>
+ <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
+ <translation>Kết nối đến máy chủ Bitcoin thông qua SOCKS5 proxy.</translation>
+ </message>
+ <message>
+ <source>Proxy &amp;IP:</source>
+ <translation>Proxy &amp;IP:</translation>
+ </message>
+ <message>
+ <source>&amp;Port:</source>
+ <translation>&amp;Cổng:</translation>
+ </message>
+ <message>
+ <source>Port of the proxy (e.g. 9050)</source>
+ <translation>Cổng proxy (e.g. 9050) </translation>
+ </message>
+ <message>
+ <source>IPv4</source>
+ <translation>IPv4</translation>
+ </message>
+ <message>
+ <source>IPv6</source>
+ <translation>IPv6</translation>
+ </message>
+ <message>
<source>&amp;Display</source>
<translation>&amp;Hiển thị</translation>
</message>
<message>
+ <source>User Interface &amp;language:</source>
+ <translation>Giao diện người dùng &amp; ngôn ngữ</translation>
+ </message>
+ <message>
<source>&amp;OK</source>
<translation>&amp;OK</translation>
</message>
@@ -307,6 +559,10 @@
<source>default</source>
<translation>mặc định</translation>
</message>
+ <message>
+ <source>none</source>
+ <translation>Trống</translation>
+ </message>
</context>
<context>
<name>OverviewPage</name>
@@ -315,11 +571,22 @@
<translation>Form</translation>
</message>
<message>
+ <source>Available:</source>
+ <translation>Khả dụng</translation>
+ </message>
+ <message>
+ <source>Pending:</source>
+ <translation>Đang chờ</translation>
+ </message>
+ <message>
<source>Total:</source>
<translation>Tổng:</translation>
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
<message>
<source>User Agent</source>
@@ -332,6 +599,20 @@
<source>Amount</source>
<translation>Lượng</translation>
</message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 và %2</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>$Lưu hình ảnh...</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -359,6 +640,58 @@
<source>User Agent</source>
<translation>User Agent</translation>
</message>
+ <message>
+ <source>1 &amp;hour</source>
+ <translation>1&amp;giờ</translation>
+ </message>
+ <message>
+ <source>1 &amp;day</source>
+ <translation>1&amp;ngày</translation>
+ </message>
+ <message>
+ <source>1 &amp;week</source>
+ <translation>1&amp;tuần</translation>
+ </message>
+ <message>
+ <source>1 &amp;year</source>
+ <translation>1&amp;năm</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>Sử dụng phím lên và xuống để di chuyển lịch sử, và &lt;b&gt;Ctrl-L&lt;/b&gt; để xóa màn hình</translation>
+ </message>
+ <message>
+ <source>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</source>
+ <translation>Gõ &lt;b&gt;help&lt;/b&gt; để xem nhưng câu lệnh có sẵn</translation>
+ </message>
+ <message>
+ <source>%1 B</source>
+ <translation>%1 B</translation>
+ </message>
+ <message>
+ <source>%1 KB</source>
+ <translation>%1 KB</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <translation>%1 MB</translation>
+ </message>
+ <message>
+ <source>%1 GB</source>
+ <translation>%1 GB</translation>
+ </message>
+ <message>
+ <source>never</source>
+ <translation>không bao giờ</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Đồng ý</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Không</translation>
+ </message>
</context>
<context>
<name>ReceiveCoinsDialog</name>
@@ -366,17 +699,124 @@
<source>&amp;Amount:</source>
<translation>Lượng:</translation>
</message>
+ <message>
+ <source>&amp;Label:</source>
+ <translation>&amp;Nhãn</translation>
+ </message>
+ <message>
+ <source>&amp;Message:</source>
+ <translation>&amp;Tin nhắn:</translation>
+ </message>
+ <message>
+ <source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
+ <translation>Sử dụng form này để yêu cầu thanh toán. Tất cả các trường &lt;b&gt;không bắt buộc&lt;b&gt;</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation>Xóa tất cả các trường trong biểu mẫu</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Xóa</translation>
+ </message>
+ <message>
+ <source>Requested payments history</source>
+ <translation>Lịch sử yêu cầu thanh toán</translation>
+ </message>
+ <message>
+ <source>&amp;Request payment</source>
+ <translation>&amp;Yêu cầu thanh toán</translation>
+ </message>
+ <message>
+ <source>Show</source>
+ <translation>Hiển thị</translation>
+ </message>
+ <message>
+ <source>Remove the selected entries from the list</source>
+ <translation>Xóa khỏi danh sách</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation>Xóa</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Copy tin nhắn</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>QR Code</source>
+ <translation>QR Code</translation>
+ </message>
+ <message>
+ <source>Copy &amp;URI</source>
+ <translation>Copy &amp;URI</translation>
+ </message>
+ <message>
<source>Copy &amp;Address</source>
<translation>&amp;Copy Địa Chỉ</translation>
</message>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>$Lưu hình ảnh...</translation>
+ </message>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Yêu cầu thanh toán cho %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Thông tin thanh toán</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Lượng</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Tin nhắn</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Lỗi khi encode từ URI thành QR Code</translation>
+ </message>
+</context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Message</source>
+ <translation>Tin nhắn</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(không tin nhắn)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
<message>
+ <source>Send Coins</source>
+ <translation>Gửi Coins</translation>
+ </message>
+ <message>
+ <source>Coin Control Features</source>
+ <translation>Tính năng Control Coin</translation>
+ </message>
+ <message>
+ <source>Inputs...</source>
+ <translation>Nhập...</translation>
+ </message>
+ <message>
+ <source>automatically selected</source>
+ <translation>Tự động chọn</translation>
+ </message>
+ <message>
<source>Insufficient funds!</source>
<translation>Không đủ tiền</translation>
</message>
@@ -393,17 +833,93 @@
<translation>Lượng:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>Tầm quan trọng:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>Phí:</translation>
</message>
<message>
+ <source>After Fee:</source>
+ <translation>Sau thuế, phí:</translation>
+ </message>
+ <message>
<source>Change:</source>
<translation>Thay đổi:</translation>
</message>
+ <message>
+ <source>Transaction Fee:</source>
+ <translation>Phí giao dịch</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Chọn...</translation>
+ </message>
+ <message>
+ <source>collapse fee-settings</source>
+ <translation>Thu gọn fee-settings</translation>
+ </message>
+ <message>
+ <source>per kilobyte</source>
+ <translation>trên KB</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Ẩn</translation>
+ </message>
+ <message>
+ <source>total at least</source>
+ <translation>Tổng cộng ít nhất</translation>
+ </message>
+ <message>
+ <source>(read the tooltip)</source>
+ <translation>(Đọc hướng dẫn)</translation>
+ </message>
+ <message>
+ <source>normal</source>
+ <translation>Bình thường</translation>
+ </message>
+ <message>
+ <source>fast</source>
+ <translation>Nhanh</translation>
+ </message>
+ <message>
+ <source>Send to multiple recipients at once</source>
+ <translation>Gửi đến nhiều người nhận trong một lần</translation>
+ </message>
+ <message>
+ <source>Add &amp;Recipient</source>
+ <translation>Thêm &amp;Người nhận</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation>Xóa tất cả các trường trong biểu mẫu</translation>
+ </message>
+ <message>
+ <source>Clear &amp;All</source>
+ <translation>Xóa &amp;Tất cả</translation>
+ </message>
+ <message>
+ <source>Balance:</source>
+ <translation>Tài khoản</translation>
+ </message>
+ <message>
+ <source>Confirm the send action</source>
+ <translation>Xác nhận sự gửi</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 đến %2</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Tổng cộng %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>hoặc</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Xác nhận gửi coins</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -411,12 +927,27 @@
<source>A&amp;mount:</source>
<translation>Lượng:</translation>
</message>
+ <message>
+ <source>&amp;Label:</source>
+ <translation>&amp;Nhãn</translation>
+ </message>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Đồng ý</translation>
+ </message>
+</context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
<name>SignVerifyMessageDialog</name>
+ <message>
+ <source>Clear &amp;All</source>
+ <translation>Xóa &amp;Tất cả</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -425,12 +956,42 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Message</source>
+ <translation>Tin nhắn</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Lượng</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Gửi Coins</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
<message>
<source>Options:</source>
diff --git a/src/qt/locale/bitcoin_zh.ts b/src/qt/locale/bitcoin_zh.ts
index bceba9dfdd..99d723deff 100644
--- a/src/qt/locale/bitcoin_zh.ts
+++ b/src/qt/locale/bitcoin_zh.ts
@@ -3,6 +3,9 @@
<name>AddressBookPage</name>
</context>
<context>
+ <name>AddressTableModel</name>
+ </context>
+<context>
<name>AskPassphraseDialog</name>
</context>
<context>
@@ -43,6 +46,9 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -52,12 +58,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -67,6 +82,13 @@
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>日期</translation>
+ </message>
+ </context>
+<context>
<name>SendCoinsDialog</name>
<message>
<source>Insufficient funds!</source>
@@ -76,11 +98,26 @@
<source>Choose...</source>
<translation>选择...</translation>
</message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>收款人地址无效,请再次确认。</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>
</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -93,17 +130,43 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation>日期</translation>
+ </message>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
- <name>UnitDisplayStatusBarControl</name>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>日期</translation>
+ </message>
</context>
<context>
- <name>bitcoin-core</name>
+ <name>TransactionView</name>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>转账额度须为正数</translation>
+ <source>Date</source>
+ <translation>日期</translation>
</message>
+ </context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
+ <name>bitcoin-core</name>
<message>
<source>Transaction too large for fee policy</source>
<translation>根据费率标准,本次转账超额</translation>
diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts
index 92a7006d30..20875c2327 100644
--- a/src/qt/locale/bitcoin_zh_CN.ts
+++ b/src/qt/locale/bitcoin_zh_CN.ts
@@ -41,6 +41,77 @@
<source>&amp;Delete</source>
<translation>删除(&amp;D)</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>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>
+ <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>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>重复新密码</translation>
</message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>输入钱包的新密码。&lt;br/&gt;密码请用&lt;b&gt;10 个以上的随机字符&lt;/b&gt;,或是&lt;b&gt;8 个以上的字词&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>提供的密码不yi'zhi。</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>警告: 大写字母锁定已开启!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -112,7 +271,11 @@
</message>
<message>
<source>&amp;About %1</source>
- <translation>&amp;关于 %1</translation>
+ <translation>关于 %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>显示 %1 相关信息</translation>
</message>
<message>
<source>About &amp;Qt</source>
@@ -127,6 +290,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>
@@ -151,6 +318,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>
@@ -232,7 +411,7 @@
</message>
<message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation>请求支付(生成二维码和 bitcoin: URI)</translation>
+ <translation>请求支付 (生成二维码和 bitcoin: URI)</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
@@ -244,7 +423,7 @@
</message>
<message>
<source>Open a bitcoin: URI or payment request</source>
- <translation>打开一个比特币:URI 或支付请求</translation>
+ <translation>打开一个 bitcoin: URI 或支付请求</translation>
</message>
<message>
<source>&amp;Command-line options</source>
@@ -255,32 +434,16 @@
<translation><numerusform>%n 个到比特币网络的活动连接</numerusform></translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>沒有可用的区块来源...</translation>
- </message>
- <message numerus="yes">
- <source>Processed %n block(s) of transaction history.</source>
- <translation><numerusform>已处理 %n 个交易历史数据块。</numerusform></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>
+ <source>Indexing blocks on disk...</source>
+ <translation>正在为数据块建立索引...</translation>
</message>
<message>
- <source>%1 and %2</source>
- <translation>%1 和 %2</translation>
+ <source>Processing blocks on disk...</source>
+ <translation>正在处理数据块...</translation>
</message>
<message numerus="yes">
- <source>%n year(s)</source>
- <translation><numerusform>%n 年</numerusform></translation>
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>已处理 %n 个交易历史数据块。</numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -311,6 +474,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>
@@ -360,12 +535,16 @@
<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>
+ <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>
<source>Coin Selection</source>
- <translation>币源选择(Coin Selection)</translation>
+ <translation>选择钱币</translation>
</message>
<message>
<source>Quantity:</source>
@@ -380,10 +559,6 @@
<translation>金额:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>优先级:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>费用:</translation>
</message>
@@ -436,8 +611,84 @@
<translation>已确认</translation>
</message>
<message>
- <source>Priority</source>
- <translation>优先级</translation>
+ <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>(%1 locked)</source>
+ <translation>(锁定 %1 枚)</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 个 satoshi 的误差。</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>
@@ -462,6 +713,38 @@
<source>&amp;Address</source>
<translation>地址(&amp;A)</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>
+ <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>
@@ -497,6 +780,10 @@
<translation>(%1 位)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>關於 %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>命令行选项</translation>
</message>
@@ -532,7 +819,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>
@@ -540,6 +831,19 @@
<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>%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>
+ <message>
<source>Use the default data directory</source>
<translation>使用默认的数据目录</translation>
</message>
@@ -565,6 +869,53 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <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>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -582,6 +933,10 @@
<source>Select payment request file</source>
<translation>选择付款请求文件 </translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>选择要打开的付款请求文件</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -594,6 +949,14 @@
<translation>主要(&amp;M)</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>系统登入时启动 %1</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>数据库缓存大小(&amp;D)</translation>
</message>
@@ -719,7 +1082,7 @@
</message>
<message>
<source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source>
- <translation>在Tor匿名网络下通过不同的SOCKS5代理连接比特币网络</translation>
+ <translation>在 Tor 匿名网络下通过不同的 SOCKS5 代理连接比特币网络</translation>
</message>
<message>
<source>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</source>
@@ -730,6 +1093,14 @@
<translation>窗口(&amp;W)</translation>
</message>
<message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>不在通知区显示图标</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>
@@ -750,6 +1121,10 @@
<translation>用户界面语言(&amp;L):</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;U):</translation>
</message>
@@ -806,7 +1181,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>现在显示的消息可能是过期的. 在连接上比特币网络节点后,您的钱包将自动与网络同步,但是这个过程还没有完成。</translation>
+ <translation>现在显示的消息可能是过期的。在连接上比特币网络节点后,您的钱包将自动与网络同步,但是这个过程还没有完成。</translation>
</message>
<message>
<source>Watch-only:</source>
@@ -874,6 +1249,98 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>要求付款时发生错误</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>无法启动 bitcoin 协议的“
+一键支付”处理器</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>URI 处理</translation>
+ </message>
+ <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>
<source>User Agent</source>
@@ -884,8 +1351,12 @@
<translation>节点/服务</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Ping 时间</translation>
+ <source>NodeId</source>
+ <translation>节点ID</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation> </translation>
</message>
</context>
<context>
@@ -926,6 +1397,72 @@
<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>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 尚未安全退出</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <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语法。</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>错误:%1</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>保存图片(&amp;S)...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>复制图片</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>保存二维码</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG 图像(*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -954,6 +1491,10 @@
<translation>使用的 BerkeleyDB 版本</translation>
</message>
<message>
+ <source>Datadir</source>
+ <translation>数据目录</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>启动时间</translation>
</message>
@@ -1038,6 +1579,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>
@@ -1062,10 +1611,18 @@
<translation>Ping 时间</translation>
</message>
<message>
+ <source>The duration of a currently outstanding ping.</source>
+ <translation>目前这一次 ping 已经过去的时间。</translation>
+ </message>
+ <message>
<source>Ping Wait</source>
<translation>Ping等待</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>最小Ping值</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>时间偏移</translation>
</message>
@@ -1095,7 +1652,7 @@
</message>
<message>
<source>In:</source>
- <translation>输入:</translation>
+ <translation>输入:</translation>
</message>
<message>
<source>Out:</source>
@@ -1110,14 +1667,6 @@
<translation>清空控制台</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>(&amp;D)断开节点连接</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>禁止节点连接时长:</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 小时(&amp;H)</translation>
</message>
@@ -1134,8 +1683,20 @@
<translation>1 年(&amp;Y)</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>(&amp;U)允许节点连接</translation>
+ <source>&amp;Disconnect</source>
+ <translation>(&amp;D)断开</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>禁止</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>重新允许</translation>
+ </message>
+ <message>
+ <source>Welcome to the %1 RPC console.</source>
+ <translation>欢迎使用 %1 的 RPC 控制台。</translation>
</message>
<message>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
@@ -1146,6 +1707,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>
@@ -1264,6 +1833,22 @@
<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>
@@ -1283,6 +1868,73 @@
<source>&amp;Save Image...</source>
<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>
+ <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 编码成二维码时发生错误。</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>
+ <message>
+ <source>Requested</source>
+ <translation>总额</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1319,10 +1971,6 @@
<translation>金额:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>优先级:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>费用:</translation>
</message>
@@ -1391,10 +2039,6 @@
<translation>(智能交易费用 尚未初始化。 需要再下载一些数据块...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>确认时间:</translation>
- </message>
- <message>
<source>normal</source>
<translation>一般</translation>
</message>
@@ -1434,6 +2078,122 @@
<source>S&amp;end</source>
<translation>发送(&amp;E)</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>%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>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>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1513,10 +2273,25 @@
<source>Memo:</source>
<translation>便条:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>为这个地址输入一个标签,以便将它添加到您的地址簿</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>是</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down...</source>
+ <translation>正在关闭 %1 ...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation>在此窗口消失前不要关闭计算机。</translation>
</message>
@@ -1607,6 +2382,58 @@
<source>Reset all verify message fields</source>
<translation>清空所有验证消息栏</translation>
</message>
+ <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>
@@ -1623,11 +2450,448 @@
</message>
</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>
+ <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>观察地址(watch-only) </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 个数据块后成熟(mature) </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>
+<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>Open until %1</source>
+ <translation>至 %1 个数据块时开启</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>掉线</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</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>观察地址(watch-only) </translation>
+ </message>
+ <message>
+ <source>(n/a)</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>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>该交易中是否涉及 观察地址(watch-only address)。</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>复制交易识别码</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>Confirmed</source>
+ <translation>已确认</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>观察地址(Watch-only) </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>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>导出失败</translation>
+ </message>
+ <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>
@@ -1637,6 +2901,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>没有载入钱包。</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>发送比特币</translation>
+ </message>
+</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>
+ <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>
<source>Options:</source>
@@ -1674,10 +2987,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>
@@ -1704,16 +3013,12 @@
<translation>无法启动HTTP服务,查看日志获取更多信息</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>接受来自外部的连接 (缺省: 如果不带 -proxy or -connect 参数设置为1)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
- <translation>比特币核心</translation>
+ <translation>Bitcoin Core</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>-fallbackfree 交易费设置得很高!这是在费用估计不可用时你可能会支付的交易费。</translation>
+ <source>The %s developers</source>
+ <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>
@@ -1732,18 +3037,10 @@
<translation>删除钱包的所有交易记录,且只有用 -rescan参数启动客户端才能重新取回交易记录 </translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>当最佳区块变化时执行命令 (命令行中的 %s 会被替换成区块哈希值)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>强制关联来自白名单同行的交易即使他们违反本地关联政策(默认: %d)</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>
@@ -1752,26 +3049,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>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
<translation>使用UPnP暴露本机监听端口(默认:1 当正在监听且不使用代理)</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>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>节点白名单,网络掩码或IP址。可多次指定。</translation>
- </message>
- <message>
<source>-maxmempool must be at least %d MB</source>
<translation>-maxmempool 最小为%d MB</translation>
</message>
@@ -1788,14 +3069,18 @@
<translation>数据块创建选项:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>仅连接到指定节点</translation>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>无法解析 - %s 地址: '%s'</translation>
</message>
<message>
<source>Connection options:</source>
<translation>连接选项:</translation>
</message>
<message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>版权所有 (C) %i-%i</translation>
+ </message>
+ <message>
<source>Corrupted block database detected</source>
<translation>检测发现数据块数据库损坏。请使用 -reindex参数重启客户端。</translation>
</message>
@@ -1840,6 +3125,10 @@
<translation>Error initializing wallet database environment %s!</translation>
</message>
<message>
+ <source>Error loading %s</source>
+ <translation>载入 %s 时发生错误</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>导入数据块数据库出错</translation>
</message>
@@ -1880,10 +3169,6 @@
<translation>认证Cookie的位置 (默认: data目录)</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>我们关联和挖掘的每sigop的最低交易字节(默认: %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>没有足够的文件描述符可用。</translation>
</message>
@@ -1916,6 +3201,10 @@
<translation>指定钱包文件(数据目录内)</translation>
</message>
<message>
+ <source>The source code is available from %s.</source>
+ <translation>源代码可以在 %s 获得。</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>忽略不支持的选项 -benchmark,使用 -debug=bench</translation>
</message>
@@ -1932,16 +3221,20 @@
<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>
<message>
<source>Verifying blocks...</source>
- <translation>正在验证数据库的完整性...</translation>
+ <translation>正在验证区块...</translation>
</message>
<message>
<source>Verifying wallet...</source>
- <translation>正在检测钱包的完整性...</translation>
+ <translation>正在验证钱包...</translation>
</message>
<message>
<source>Wallet %s resides outside data directory %s</source>
@@ -1996,10 +3289,6 @@
<translation>Maximum size of data in data carrier transactions we relay and mine (default: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>通过DNS查询每个地址,如果短地址 (默认值: 1 除非 -连接)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>为每个代理连接随机化凭据。这将启用 Tor 流隔离 (默认: %u)</translation>
</message>
@@ -2012,10 +3301,6 @@
<translation>在交易费被扣除后发送的交易金额太小</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</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 banned ,且转发所有来自他们的交易(即便这些交易已经存在于mempool中),常用于网关 </translation>
</message>
@@ -2044,6 +3329,10 @@
<translation>读取数据库出错,关闭中。</translation>
</message>
<message>
+ <source>Imports blocks from external blk000??.dat file on startup</source>
+ <translation>启动时从其他来源的 blk000??.dat 文件导入区块</translation>
+ </message>
+ <message>
<source>Information</source>
<translation>信息</translation>
</message>
@@ -2072,6 +3361,10 @@
<translation>RPC 服务器选项:</translation>
</message>
<message>
+ <source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
+ <translation>因为系统的限制,将 -maxconnections 参数从 %d 降到了 %d</translation>
+ </message>
+ <message>
<source>Rescan the block chain for missing wallet transactions on startup</source>
<translation>重新扫描区块链以查找遗漏的钱包交易</translation>
</message>
@@ -2104,12 +3397,16 @@
<translation>这是实验性的软件。</translation>
</message>
<message>
- <source>Transaction amount too small</source>
- <translation>交易量太小</translation>
+ <source>Tor control port password (default: empty)</source>
+ <translation>Tor 控制端口密码 (默认值: 空白)</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>交易金额必须是积极的</translation>
+ <source>Tor control port to use if onion listening enabled (default: %s)</source>
+ <translation>开启监听 onion 连接时的 Tor 控制端口号 (默认值: %s)</translation>
+ </message>
+ <message>
+ <source>Transaction amount too small</source>
+ <translation>交易量太小</translation>
</message>
<message>
<source>Transaction too large for fee policy</source>
@@ -2136,12 +3433,16 @@
<translation>警告</translation>
</message>
<message>
+ <source>Warning: unknown new rules activated (versionbit %i)</source>
+ <translation>警告: 不明的交易规则被启用了(versionbit %i)</translation>
+ </message>
+ <message>
<source>Whether to operate in a blocks only mode (default: %u)</source>
<translation>是否用块方进行 (%u)</translation>
</message>
<message>
<source>Zapping all transactions from wallet...</source>
- <translation>Zapping all transactions from wallet...</translation>
+ <translation>正在消除錢包中的所有交易...</translation>
</message>
<message>
<source>ZeroMQ notification options:</source>
@@ -2169,6 +3470,18 @@
<translation>(1 = 保留 tx meta data , 如 account owner 和 payment request information, 2 = 不保留 tx meta data) </translation>
</message>
<message>
+ <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
+ <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>
+ </message>
+ <message>
+ <source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
+ <translation>当产生交易时,如果每千字节 (kB) 的手续费比这个值 (单位是 %s) 低,就视为没支付手续费 (默认值: %s)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>数据块验证 严密级别 -checkblocks (0-4, 默认: %u) </translation>
</message>
@@ -2185,10 +3498,22 @@
<translation>输出调试信息 (默认: %u, 提供 &lt;category&gt; 是可选项)</translation>
</message>
<message>
+ <source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
+ <translation>支持用 Bloom 过滤器来过滤区块和交易(默认值: %u)</translation>
+ </message>
+ <message>
+ <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
+ <translation>网络版本字符串的总长度 (%i) 超过最大长度 (%i) 了。请减少 uacomment 参数的数目或长度。</translation>
+ </message>
+ <message>
<source>Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)</source>
<translation>尝试保持上传带宽低于(MiB/24h),0=无限制(默认:%d)</translation>
</message>
<message>
+ <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source>
+ <translation>找到不再支持的 -socks 参数。现在只支持 SOCKS5 协议的代理服务器,因此不可以指定 SOCKS 协议版本。</translation>
+ </message>
+ <message>
<source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
<translation>一个不被支持的参数 -whitelistalwaysrelay 被忽略了。请使用 -whitelistrelay 或者 -whitelistforcerelay.</translation>
</message>
@@ -2261,10 +3586,6 @@
<translation>设置私钥池大小为 &lt;n&gt; (默认:%u) </translation>
</message>
<message>
- <source>Set minimum block size in bytes (default: %u)</source>
- <translation>设置数据块 最小字节数 (默认: %u) </translation>
- </message>
- <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>设置RPC服务线程数 (默认: %d) </translation>
</message>
@@ -2285,6 +3606,10 @@
<translation>付款时允许使用未确认的零钱 (默认: %u) </translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>正在启动网络线程...</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>断开 非礼节点的阀值 (默认: %u) </translation>
</message>
@@ -2298,7 +3623,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_zh_HK.ts b/src/qt/locale/bitcoin_zh_HK.ts
index aa014db0bd..2f3a8d1f16 100644
--- a/src/qt/locale/bitcoin_zh_HK.ts
+++ b/src/qt/locale/bitcoin_zh_HK.ts
@@ -41,7 +41,10 @@
<source>&amp;Delete</source>
<translation>刪除 &amp;D</translation>
</message>
-</context>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -60,7 +63,7 @@
<source>Repeat new passphrase</source>
<translation>重複新密碼</translation>
</message>
-</context>
+ </context>
<context>
<name>BanTableModel</name>
<message>
@@ -215,6 +218,9 @@
<name>Intro</name>
</context>
<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
<name>OpenURIDialog</name>
</context>
<context>
@@ -224,12 +230,21 @@
<name>OverviewPage</name>
</context>
<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
<name>PeerTableModel</name>
</context>
<context>
<name>QObject</name>
</context>
<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
<name>RPCConsole</name>
</context>
<context>
@@ -239,12 +254,18 @@
<name>ReceiveRequestDialog</name>
</context>
<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
<name>SendCoinsDialog</name>
</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
<name>ShutdownWindow</name>
</context>
<context>
@@ -257,12 +278,30 @@
<name>TrafficGraphWidget</name>
</context>
<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
<name>TransactionDescDialog</name>
</context>
<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ </context>
+<context>
<name>UnitDisplayStatusBarControl</name>
</context>
<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
<name>bitcoin-core</name>
</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 ab56f96795..bd0533a83e 100644
--- a/src/qt/locale/bitcoin_zh_TW.ts
+++ b/src/qt/locale/bitcoin_zh_TW.ts
@@ -41,6 +41,77 @@
<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>這些是你要付款過去的 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>複製位址</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>複製標記</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>編輯</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>匯出位址清單</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>逗點分隔資料檔(*.csv)</translation>
+ </message>
+ <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>
+ <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>
@@ -60,6 +131,94 @@
<source>Repeat new passphrase</source>
<translation>重複新密碼</translation>
</message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>輸入錢包的新密碼。&lt;br/&gt;密碼請用&lt;b&gt;10 個以上的隨機字元&lt;/b&gt;,或是&lt;b&gt;8 個以上的字詞&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;失去其中所有的 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 現在要關閉,好完成加密程序。請注意,加密錢包不能完全防止入侵你的電腦的惡意程式偷取錢幣。</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>警告: 大寫字母鎖定作用中!</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -159,6 +318,22 @@
<translation>開啓 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>
@@ -270,34 +445,10 @@
<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>
</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>
<message>
<source>%1 behind</source>
<translation>落後 %1</translation>
@@ -335,6 +486,10 @@
<translation>%1 客戶端軟體</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>正在跟其他節點連線中...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>正在趕進度...</translation>
</message>
@@ -377,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>
@@ -384,6 +547,10 @@
<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>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>發生了致命的錯誤。Bitcoin 軟體沒辦法再繼續安全執行,只好結束。</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
@@ -404,10 +571,6 @@
<translation>金額:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>優先度:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>手續費:</translation>
</message>
@@ -460,8 +623,84 @@
<translation>已確認</translation>
</message>
<message>
- <source>Priority</source>
- <translation>優先度</translation>
+ <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>(%1 locked)</source>
+ <translation>(鎖定 %1 枚)</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 個 satoshi 的誤差。</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>
@@ -486,6 +725,38 @@
<source>&amp;Address</source>
<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>
+ <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>
@@ -609,6 +880,57 @@
</message>
</context>
<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <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>最近的交易可能還看不到,因此錢包餘額可能不正確。在錢包軟體完成跟 bitcoin 網路的同步後,這裡的資訊就會正確。詳情請見下面。</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>使用還沒顯示出來的交易所影響到的 bitcoin 可能會不被網路所接受。</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>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>不明。正在同步前導資料(%1)中...</translation>
+ </message>
+</context>
+<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
@@ -626,6 +948,10 @@
<source>Select payment request file</source>
<translation>選擇付款要求資料檔</translation>
</message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>選擇要開啟的付款要求資料檔</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -938,6 +1264,97 @@
</message>
</context>
<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>要求付款時發生錯誤</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>沒辦法啟動 bitcoin 協議的「按就付」處理器</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>URI 處理</translation>
+ </message>
+ <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 位址!可能是因為 Bitcoin 位址無效,或是 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>
<source>User Agent</source>
@@ -948,8 +1365,12 @@
<translation>節點/服務</translation>
</message>
<message>
- <source>Ping Time</source>
- <translation>Ping 時間</translation>
+ <source>NodeId</source>
+ <translation>節點識別碼</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping 時間</translation>
</message>
</context>
<context>
@@ -990,6 +1411,72 @@
<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>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 還沒有安全地結束...</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <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>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>儲存圖片...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>複製圖片</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>儲存 QR Code</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG 圖檔(*.png)</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1150,6 +1637,10 @@
<translation>Ping 等待時間</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Ping 最短時間</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>時間差</translation>
</message>
@@ -1194,14 +1685,6 @@
<translation>清主控台</translation>
</message>
<message>
- <source>&amp;Disconnect Node</source>
- <translation>跟節點斷線</translation>
- </message>
- <message>
- <source>Ban Node for</source>
- <translation>禁止節點連線:</translation>
- </message>
- <message>
<source>1 &amp;hour</source>
<translation>1 小時</translation>
</message>
@@ -1218,8 +1701,16 @@
<translation>1 年</translation>
</message>
<message>
- <source>&amp;Unban Node</source>
- <translation>解禁節點連線</translation>
+ <source>&amp;Disconnect</source>
+ <translation>斷線</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>禁止連線</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>連線解禁</translation>
</message>
<message>
<source>Welcome to the %1 RPC console.</source>
@@ -1234,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 B (位元組)</translation>
</message>
@@ -1352,6 +1851,22 @@
<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>
@@ -1371,6 +1886,73 @@
<source>&amp;Save Image...</source>
<translation>儲存圖片...</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>
+ <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 Code 時發生錯誤。</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>
+ <message>
+ <source>Requested</source>
+ <translation>要求金額</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1407,10 +1989,6 @@
<translation>金額:</translation>
</message>
<message>
- <source>Priority:</source>
- <translation>優先度:</translation>
- </message>
- <message>
<source>Fee:</source>
<translation>手續費:</translation>
</message>
@@ -1479,10 +2057,6 @@
<translation>(手續費智慧演算法還沒準備好。通常都要等幾個區塊才行...)</translation>
</message>
<message>
- <source>Confirmation time:</source>
- <translation>確認時間:</translation>
- </message>
- <message>
<source>normal</source>
<translation>正常</translation>
</message>
@@ -1507,6 +2081,10 @@
<translation>零散錢:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>目標確認時間:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>全部清掉</translation>
</message>
@@ -1522,6 +2100,122 @@
<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>
+ <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 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>付款金額必須大於零。</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>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>警告: Bitcoin 位址無效</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>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -1601,6 +2295,17 @@
<source>Memo:</source>
<translation>備註:</translation>
</message>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>請輸入這個位址的標記來把它加進位址簿中</translation>
+ </message>
+</context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>是</translation>
+ </message>
</context>
<context>
<name>ShutdownWindow</name>
@@ -1699,6 +2404,58 @@
<source>Reset all verify message fields</source>
<translation>重設所有訊息驗證欄位</translation>
</message>
+ <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>
@@ -1715,11 +2472,460 @@
</message>
</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>
+ <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>交易識別碼</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>
+ <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 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>確認中(已經 %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>watch-only</source>
+ <translation>只能看</translation>
+ </message>
+ <message>
+ <source>(n/a)</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>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>使用者定義的交易動機或理由。</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>複製交易識別碼</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>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>
+ <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>
@@ -1729,6 +2935,55 @@
</message>
</context>
<context>
+ <name>WalletFrame</name>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>沒有載入錢包。</translation>
+ </message>
+</context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>付款</translation>
+ </message>
+</context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>匯出</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>
<source>Options:</source>
@@ -1752,6 +3007,18 @@
</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; 或是值為 1 就會輸出所有的除錯資訊。</translation>
</message>
@@ -1764,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>
@@ -1792,10 +3055,6 @@
<translation>無法啟動 HTTP 伺服器。詳情請看除錯紀錄。</translation>
</message>
<message>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
- <translation>是否接受外來連線(預設值: 當沒有 -proxy 或 -connect 時為 1)</translation>
- </message>
- <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
@@ -1804,10 +3063,6 @@
<translation>%s 開發人員</translation>
</message>
<message>
- <source>-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.</source>
- <translation>警告: -fallbackfee 設定了很高的金額!這是當預估手續費還沒計算出來時,交易付款預設會付的手續費。</translation>
- </message>
- <message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
<translation>當沒有足夠的資料計算預估手續費時,所使用的手續費費率(單位是 %s/kB, 預設值: %s)</translation>
</message>
@@ -1828,10 +3083,6 @@
<translation>清掉錢包裡的所有交易,並且在下次啟動時,使用 -rescan 來從區塊鏈中復原回來。</translation>
</message>
<message>
- <source>Distributed under the MIT software license, see the accompanying file COPYING or &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</source>
- <translation>這套軟體是依據 MIT 軟體授權條款散布,詳情請見附帶的 COPYING 檔案,或是以下網站: &lt;http://www.opensource.org/licenses/mit-license.php&gt;.</translation>
- </message>
- <message>
<source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
<translation>載入 %s 發生錯誤:不能對已存在的非 HD 錢包啟用 HD 功能。</translation>
</message>
@@ -1844,8 +3095,12 @@
<translation>當錢包有交易改變時要執行的指令(指令中的 %s 會被取代成交易識別碼)</translation>
</message>
<message>
- <source>Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)</source>
- <translation>強制轉發從白名點節點收到的交易,即使它們違反了本機的轉發準則(預設值: %d)</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, 測試網路: %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>
@@ -1864,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>
@@ -1873,7 +3136,7 @@
</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>
+ <translation>這是個還沒發表的測試版本 - 使用請自負風險 - 請不要用來開採或做商業應用</translation>
</message>
<message>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
@@ -1884,18 +3147,22 @@
<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>
+ <message>
<source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
- <translation>警告: 節點網路對於區塊鏈結的決定目前有分歧!看來有些礦工會有問題。</translation>
+ <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>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
- <translation>把來自指定網域或位址的節點放進白名單。這個選項可以設定多次。</translation>
- </message>
- <message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation>改變 -txindex 參數後,必須要用 -reindex-chainstate 參數來重建資料庫</translation>
</message>
@@ -1928,12 +3195,12 @@
<translation>沒辦法解析 -%s 參數指定的位址: '%s'</translation>
</message>
<message>
- <source>Change index out of range</source>
- <translation>找零的索引值超出範圍</translation>
+ <source>Chain selection options:</source>
+ <translation>區塊鏈選項:</translation>
</message>
<message>
- <source>Connect only to the specified node(s)</source>
- <translation>只連線到指定節點(可多個)</translation>
+ <source>Change index out of range</source>
+ <translation>找零的索引值超出範圍</translation>
</message>
<message>
<source>Connection options:</source>
@@ -2056,10 +3323,6 @@
<translation>認證 cookie 資料的位置(預設值: 同資料目錄)</translation>
</message>
<message>
- <source>Minimum bytes per sigop in transactions we relay and mine (default: %u)</source>
- <translation>轉發和開採時,對交易資料的 sigop 平均位元組數下限(預設值: %u)</translation>
- </message>
- <message>
<source>Not enough file descriptors available.</source>
<translation>檔案描述元不足。</translation>
</message>
@@ -2093,17 +3356,13 @@
</message>
<message>
<source>Rewinding blocks...</source>
- <translation>倒轉回區塊鏈之前的狀態...</translation>
+ <translation>正在倒轉回區塊鏈之前的狀態...</translation>
</message>
<message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>設定資料庫快取大小是多少百萬位元組(MB,範圍: %d 到 %d,預設值: %d)</translation>
</message>
<message>
- <source>Set maximum block cost (default: %d)</source>
- <translation>設定區塊成本的最大值(預設值: %d)</translation>
- </message>
- <message>
<source>Set maximum block size in bytes (default: %d)</source>
<translation>設定區塊大小上限成多少位元組(預設值: %d)</translation>
</message>
@@ -2136,6 +3395,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>
@@ -2208,10 +3471,6 @@
<translation>轉發和開採時,對只帶資料的交易的大小上限(預設值: %u)</translation>
</message>
<message>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
- <translation>是否允許在節點位址數目不足時,使用域名查詢來搜尋節點 (預設值: 當沒用 -connect 時為 1)</translation>
- </message>
- <message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
<translation>對每個代理連線使用隨機產生的憑證。這個選項會開啟 Tor 的串流隔離(預設值: %u)</translation>
</message>
@@ -2224,10 +3483,6 @@
<translation>扣除手續費後的交易金額太少而不能傳送</translation>
</message>
<message>
- <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
- <translation>此產品也包含了由 OpenSSL Project 所開發的 OpenSSL Toolkit 軟體 &lt;https://www.openssl.org/&gt;, 和由 Eric Young 撰寫的加解密軟體,以及由 Thomas Bernard 所撰寫的 UPnP 軟體。</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>
@@ -2340,10 +3595,6 @@
<translation>交易金額太小</translation>
</message>
<message>
- <source>Transaction amounts must be positive</source>
- <translation>交易金額必須是正的</translation>
- </message>
- <message>
<source>Transaction too large for fee policy</source>
<translation>根據交易手續費準則,本交易的位元量過大</translation>
</message>
@@ -2408,18 +3659,22 @@
<translation>參數 -maxtxfee 設定了很高的金額!這可是你一次交易就有可能付出的最高手續費。</translation>
</message>
<message>
- <source>-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
- <translation>參數 -paytxfee 設定了很高的金額!這可是你交易付款時所要付的手續費。</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>
</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>當製造交易時,如果每千位元組(kB)的手續費比這個值(單位是 %s)低,就視為沒付手續費(預設值: %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>
@@ -2436,10 +3691,26 @@
<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>是否允許在節點位址數目不足時,使用域名查詢來搜尋節點 (預設值: 當沒用 -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>設定非冗長模式時,回傳的交易原始資料或區塊位元值的序列化形式:無 segwit 為 0,或是有 segwit 為 1 (預設值: %d)</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<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>
<translation>網路版本字串的總長度(%i)超過最大長度(%i)了。請減少 uacomment 參數的數目或長度。</translation>
</message>
@@ -2460,10 +3731,6 @@
<translation>使用另外的 SOCK5 代理伺服器,來透過 Tor 隱藏服務跟其他節點聯絡(預設值: %s)</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. This option can be specified multiple times</source>
- <translation>JSON-RPC 連線要用的使用者名稱和雜湊密碼。&lt;userpw&gt; 的格式是:&lt;使用者名稱&gt;:&lt;調味值&gt;$&lt;雜湊值&gt;。在 share/rpcuser 目錄下有一個示範的 python 程式。這個選項可以給很多次。</translation>
- </message>
- <message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
<translation>警告: 有礦工正在開採不明版本的區塊!這表示有不明的交易規則正在作用中</translation>
</message>
@@ -2472,6 +3739,14 @@
<translation>警告: 錢包檔壞掉,但資料被救回來了!原來的檔案 %s 改儲存為 %s,在目錄 %s 下。 如果餘額或交易資料有誤的話,你應該要從備份資料復原回來。</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>把來自指定位址(例如: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>
@@ -2492,6 +3767,10 @@
<translation>無效的 -proxy 位址: '%s'</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>密鑰池已經乾了,請先執行 keypoolrefill</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>在通訊埠 &lt;port&gt; 聽候 JSON-RPC 連線(預設值: %u, 或若為測試網路: %u)</translation>
</message>
@@ -2528,12 +3807,16 @@
<translation>允許轉發非 P2SH 的多簽章交易(預設值: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>送出允許提高手續費(full-RBF)的交易(預設值: %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 minimum block size in bytes (default: %u)</source>
- <translation>設定區塊大小下限為多少位元組(預設值: %u)</translation>
+ <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>
@@ -2556,10 +3839,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/modaloverlay.cpp b/src/qt/modaloverlay.cpp
new file mode 100644
index 0000000000..4779ffa43f
--- /dev/null
+++ b/src/qt/modaloverlay.cpp
@@ -0,0 +1,172 @@
+// Copyright (c) 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 "modaloverlay.h"
+#include "ui_modaloverlay.h"
+
+#include "guiutil.h"
+
+#include "chainparams.h"
+
+#include <QResizeEvent>
+#include <QPropertyAnimation>
+
+ModalOverlay::ModalOverlay(QWidget *parent) :
+QWidget(parent),
+ui(new Ui::ModalOverlay),
+bestHeaderHeight(0),
+bestHeaderDate(QDateTime()),
+layerIsVisible(false),
+userClosed(false)
+{
+ ui->setupUi(this);
+ connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(closeClicked()));
+ if (parent) {
+ parent->installEventFilter(this);
+ raise();
+ }
+
+ blockProcessTime.clear();
+ setVisible(false);
+}
+
+ModalOverlay::~ModalOverlay()
+{
+ delete ui;
+}
+
+bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) {
+ if (obj == parent()) {
+ if (ev->type() == QEvent::Resize) {
+ QResizeEvent * rev = static_cast<QResizeEvent*>(ev);
+ resize(rev->size());
+ if (!layerIsVisible)
+ setGeometry(0, height(), width(), height());
+
+ }
+ else if (ev->type() == QEvent::ChildAdded) {
+ raise();
+ }
+ }
+ return QWidget::eventFilter(obj, ev);
+}
+
+//! Tracks parent widget changes
+bool ModalOverlay::event(QEvent* ev) {
+ if (ev->type() == QEvent::ParentAboutToChange) {
+ if (parent()) parent()->removeEventFilter(this);
+ }
+ else if (ev->type() == QEvent::ParentChange) {
+ if (parent()) {
+ parent()->installEventFilter(this);
+ raise();
+ }
+ }
+ return QWidget::event(ev);
+}
+
+void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate)
+{
+ if (count > bestHeaderHeight) {
+ bestHeaderHeight = count;
+ bestHeaderDate = blockDate;
+ }
+}
+
+void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress)
+{
+ QDateTime currentDate = QDateTime::currentDateTime();
+
+ // keep a vector of samples of verification progress at height
+ 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;
+ 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++)
+ {
+ 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;
+ timeDelta = blockProcessTime[0].first - sample.first;
+ progressPerHour = progressDelta/(double)timeDelta*1000*3600;
+ remainingMSecs = remainingProgress / progressDelta * timeDelta;
+ break;
+ }
+ }
+ // show progress increase per hour
+ ui->progressIncreasePerH->setText(QString::number(progressPerHour*100, 'f', 2)+"%");
+
+ // show expected remaining time
+ ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs/1000.0));
+
+ static const int MAX_SAMPLES = 5000;
+ if (blockProcessTime.count() > MAX_SAMPLES)
+ blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count()-MAX_SAMPLES);
+ }
+
+ // show the last block date
+ ui->newestBlockDate->setText(blockDate.toString());
+
+ // show the percentage done according to nVerificationProgress
+ ui->percentageProgress->setText(QString::number(nVerificationProgress*100, 'f', 2)+"%");
+ ui->progressBar->setValue(nVerificationProgress*100);
+
+ if (!bestHeaderDate.isValid())
+ // not syncing
+ 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) / Params().GetConsensus().nPowTargetSpacing;
+ bool hasBestHeader = bestHeaderHeight >= count;
+
+ // show remaining number of blocks
+ 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));
+ ui->expectedTimeLeft->setText(tr("Unknown..."));
+ }
+}
+
+void ModalOverlay::toggleVisibility()
+{
+ showHide(layerIsVisible, true);
+ if (!layerIsVisible)
+ userClosed = true;
+}
+
+void ModalOverlay::showHide(bool hide, bool userRequested)
+{
+ if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))
+ return;
+
+ if (!isVisible() && !hide)
+ setVisible(true);
+
+ setGeometry(0, hide ? 0 : height(), width(), height());
+
+ QPropertyAnimation* animation = new QPropertyAnimation(this, "pos");
+ animation->setDuration(300);
+ animation->setStartValue(QPoint(0, hide ? 0 : this->height()));
+ animation->setEndValue(QPoint(0, hide ? this->height() : 0));
+ animation->setEasingCurve(QEasingCurve::OutQuad);
+ animation->start(QAbstractAnimation::DeleteWhenStopped);
+ layerIsVisible = !hide;
+}
+
+void ModalOverlay::closeClicked()
+{
+ showHide(true);
+ userClosed = true;
+}
diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h
new file mode 100644
index 0000000000..21ccdbd839
--- /dev/null
+++ b/src/qt/modaloverlay.h
@@ -0,0 +1,50 @@
+// Copyright (c) 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_QT_MODALOVERLAY_H
+#define BITCOIN_QT_MODALOVERLAY_H
+
+#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;
+}
+
+/** Modal overlay to display information about the chain-sync state */
+class ModalOverlay : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit ModalOverlay(QWidget *parent);
+ ~ModalOverlay();
+
+public Q_SLOTS:
+ void tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress);
+ void setKnownBestHeight(int count, const QDateTime& blockDate);
+
+ void toggleVisibility();
+ // will show or hide the modal layer
+ void showHide(bool hide = false, bool userRequested = false);
+ void closeClicked();
+ bool isLayerVisible() { return layerIsVisible; }
+
+protected:
+ bool eventFilter(QObject * obj, QEvent * ev);
+ bool event(QEvent* ev);
+
+private:
+ Ui::ModalOverlay *ui;
+ int bestHeaderHeight; //best known height (based on the headers)
+ QDateTime bestHeaderDate;
+ QVector<QPair<qint64, double> > blockProcessTime;
+ bool layerIsVisible;
+ bool userClosed;
+};
+
+#endif // BITCOIN_QT_MODALOVERLAY_H
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index 5f31f49372..93092501c9 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Copyright (c) 2014-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.
@@ -22,9 +22,9 @@ static const struct {
static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles);
// titleAddText needs to be const char* for tr()
-NetworkStyle::NetworkStyle(const QString &appName, const int iconColorHueShift, const int iconColorSaturationReduction, const char *titleAddText):
- appName(appName),
- titleAddText(qApp->translate("SplashScreen", titleAddText))
+NetworkStyle::NetworkStyle(const QString &_appName, const int iconColorHueShift, const int iconColorSaturationReduction, const char *_titleAddText):
+ appName(_appName),
+ titleAddText(qApp->translate("SplashScreen", _titleAddText))
{
// load pixmap
QPixmap pixmap(":/icons/bitcoin");
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index a45afde566..8718929c6a 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2014 The Bitcoin Core developers
+// 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.
@@ -33,17 +33,17 @@
const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;
#endif
-Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent) :
- QObject(parent),
- parent(parent),
- programName(programName),
+Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon, QWidget *_parent) :
+ QObject(_parent),
+ parent(_parent),
+ programName(_programName),
mode(None),
- trayIcon(trayicon)
+ trayIcon(_trayIcon)
#ifdef USE_DBUS
,interface(0)
#endif
{
- if(trayicon && trayicon->supportsMessages())
+ if(_trayIcon && _trayIcon->supportsMessages())
{
mode = QSystemTray;
}
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index f2db398899..efb25aaf18 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -13,7 +13,7 @@
#include "guiutil.h"
#include "optionsmodel.h"
-#include "main.h" // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
+#include "validation.h" // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults
@@ -135,22 +135,22 @@ OptionsDialog::~OptionsDialog()
delete ui;
}
-void OptionsDialog::setModel(OptionsModel *model)
+void OptionsDialog::setModel(OptionsModel *_model)
{
- this->model = model;
+ this->model = _model;
- if(model)
+ if(_model)
{
/* check if client restart is needed and show persistent message */
- if (model->isRestartRequired())
+ if (_model->isRestartRequired())
showRestartWarning(true);
- QString strLabel = model->getOverriddenByCommandLine();
+ QString strLabel = _model->getOverriddenByCommandLine();
if (strLabel.isEmpty())
strLabel = tr("none");
ui->overriddenByCommandLineLabel->setText(strLabel);
- mapper->setModel(model);
+ mapper->setModel(_model);
setMapper();
mapper->toFirst();
@@ -232,6 +232,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 +289,9 @@ void OptionsDialog::showRestartWarning(bool fPersistent)
void OptionsDialog::clearStatusLabel()
{
ui->statusLabel->clear();
+ if (model && model->isRestartRequired()) {
+ showRestartWarning(true);
+ }
}
void OptionsDialog::updateProxyValidationState()
@@ -286,7 +301,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
{
@@ -327,7 +342,8 @@ QValidator::State ProxyAddressValidator::validate(QString &input, int &pos) cons
{
Q_UNUSED(pos);
// Validate the proxy
- proxyType addrProxy = proxyType(CService(input.toStdString(), 9050), true);
+ CService serv(LookupNumeric(input.toStdString().c_str(), 9050));
+ proxyType addrProxy = proxyType(serv, true);
if (addrProxy.IsValid())
return QValidator::Acceptable;
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index 41b56d1386..f9f5823c05 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -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 cc2cbc0e66..d6e740ee9c 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -13,9 +13,11 @@
#include "amount.h"
#include "init.h"
-#include "main.h" // For DEFAULT_SCRIPTCHECK_THREADS
+#include "validation.h" // For DEFAULT_SCRIPTCHECK_THREADS
#include "net.h"
+#include "netbase.h"
#include "txdb.h" // for -dbcache defaults
+#include "intro.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
@@ -34,7 +36,7 @@ OptionsModel::OptionsModel(QObject *parent, bool resetSettings) :
void OptionsModel::addOverriddenOption(const std::string &option)
{
- strOverriddenByCommandLine += QString::fromStdString(option) + "=" + QString::fromStdString(mapArgs[option]) + " ";
+ strOverriddenByCommandLine += QString::fromStdString(option) + "=" + QString::fromStdString(GetArg(option, "")) + " ";
}
// Writes all missing QSettings with their default values
@@ -43,6 +45,8 @@ void OptionsModel::Init(bool resetSettings)
if (resetSettings)
Reset();
+ checkAndMigrate();
+
QSettings settings;
// Ensure restart flag is unset on client startup
@@ -96,6 +100,9 @@ void OptionsModel::Init(bool resetSettings)
if (!SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
addOverriddenOption("-par");
+ if (!settings.contains("strDataDir"))
+ settings.setValue("strDataDir", Intro::getDefaultDataDirectory());
+
// Wallet
#ifdef ENABLE_WALLET
if (!settings.contains("bSpendZeroConfChange"))
@@ -148,9 +155,19 @@ void OptionsModel::Reset()
{
QSettings settings;
+ // Save the strDataDir setting
+ QString dataDir = Intro::getDefaultDataDirectory();
+ dataDir = settings.value("strDataDir", dataDir).toString();
+
// Remove all entries from our QSettings object
settings.clear();
+ // Set strDataDir
+ settings.setValue("strDataDir", dataDir);
+
+ // Set that this was reset
+ settings.setValue("fReset", true);
+
// default setting for OptionsModel::StartAtStartup - disabled
if (GUIUtil::GetStartOnSystemStartup())
GUIUtil::SetStartOnSystemStartup(false);
@@ -429,3 +446,22 @@ bool OptionsModel::isRestartRequired()
QSettings settings;
return settings.value("fRestartRequired", false).toBool();
}
+
+void OptionsModel::checkAndMigrate()
+{
+ // Migration of default values
+ // Check if the QSettings container was already loaded with this client version
+ QSettings settings;
+ static const char strSettingsVersionKey[] = "nSettingsVersion";
+ int settingsVersion = settings.contains(strSettingsVersionKey) ? settings.value(strSettingsVersionKey).toInt() : 0;
+ if (settingsVersion < CLIENT_VERSION)
+ {
+ // -dbcache was bumped from 100 to 300 in 0.13
+ // see https://github.com/bitcoin/bitcoin/pull/8273
+ // force people to upgrade to the new value if they are using 100MB
+ if (settingsVersion < 130000 && settings.contains("nDatabaseCache") && settings.value("nDatabaseCache").toLongLong() == 100)
+ settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache);
+
+ settings.setValue(strSettingsVersionKey, CLIENT_VERSION);
+ }
+}
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 3b491ceac2..78529fbdcc 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -81,12 +81,14 @@ private:
int nDisplayUnit;
QString strThirdPartyTxUrls;
bool fCoinControlFeatures;
- /* settings that were overriden by command-line */
+ /* settings that were overridden by command-line */
QString strOverriddenByCommandLine;
- /// Add option to list of GUI options overridden through command line/config file
+ // Add option to list of GUI options overridden through command line/config file
void addOverriddenOption(const std::string &option);
+ // Check settings version and upgrade default values if required
+ void checkAndMigrate();
Q_SIGNALS:
void displayUnitChanged(int unit);
void coinControlFeaturesChanged(bool);
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 6a0404cbf7..ba344f4dbf 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -25,9 +25,9 @@ class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
- TxViewDelegate(const PlatformStyle *platformStyle):
- QAbstractItemDelegate(), unit(BitcoinUnits::BTC),
- platformStyle(platformStyle)
+ TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr):
+ QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
+ platformStyle(_platformStyle)
{
}
@@ -119,8 +119,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
currentWatchOnlyBalance(-1),
currentWatchUnconfBalance(-1),
currentWatchImmatureBalance(-1),
- txdelegate(new TxViewDelegate(platformStyle)),
- filter(0)
+ txdelegate(new TxViewDelegate(platformStyle, this))
{
ui->setupUi(this);
@@ -140,6 +139,8 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
// start with displaying the "out of sync" warnings
showOutOfSyncWarning(true);
+ connect(ui->labelWalletStatus, SIGNAL(clicked()), this, SLOT(handleOutOfSyncWarningClicks()));
+ connect(ui->labelTransactionsStatus, SIGNAL(clicked()), this, SLOT(handleOutOfSyncWarningClicks()));
}
void OverviewPage::handleTransactionClicked(const QModelIndex &index)
@@ -148,6 +149,11 @@ void OverviewPage::handleTransactionClicked(const QModelIndex &index)
Q_EMIT transactionClicked(filter->mapToSource(index));
}
+void OverviewPage::handleOutOfSyncWarningClicks()
+{
+ Q_EMIT outOfSyncWarningClicked();
+}
+
OverviewPage::~OverviewPage()
{
delete ui;
@@ -213,7 +219,7 @@ void OverviewPage::setWalletModel(WalletModel *model)
if(model && model->getOptionsModel())
{
// Set up transaction list
- filter = new TransactionFilterProxy();
+ filter.reset(new TransactionFilterProxy());
filter->setSourceModel(model->getTransactionTableModel());
filter->setLimit(NUM_ITEMS);
filter->setDynamicSortFilter(true);
@@ -221,7 +227,7 @@ void OverviewPage::setWalletModel(WalletModel *model)
filter->setShowInactive(false);
filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);
- ui->listTransactions->setModel(filter);
+ ui->listTransactions->setModel(filter.get());
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
// Keep up to date with wallet
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 911443c76a..d76b651ce6 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -8,6 +8,7 @@
#include "amount.h"
#include <QWidget>
+#include <memory>
class ClientModel;
class TransactionFilterProxy;
@@ -42,6 +43,7 @@ public Q_SLOTS:
Q_SIGNALS:
void transactionClicked(const QModelIndex &index);
+ void outOfSyncWarningClicked();
private:
Ui::OverviewPage *ui;
@@ -55,13 +57,14 @@ private:
CAmount currentWatchImmatureBalance;
TxViewDelegate *txdelegate;
- TransactionFilterProxy *filter;
+ std::unique_ptr<TransactionFilterProxy> filter;
private Q_SLOTS:
void updateDisplayUnit();
void handleTransactionClicked(const QModelIndex &index);
void updateAlerts(const QString &warnings);
void updateWatchOnlyLabels(bool showWatchOnly);
+ void handleOutOfSyncWarningClicks();
};
#endif // BITCOIN_QT_OVERVIEWPAGE_H
diff --git a/src/qt/paymentrequest.proto b/src/qt/paymentrequest.proto
index b2281c4c7b..d2721a34bd 100644
--- a/src/qt/paymentrequest.proto
+++ b/src/qt/paymentrequest.proto
@@ -6,6 +6,8 @@
// https://en.bitcoin.it/wiki/Payment_Request
//
+syntax = "proto2";
+
package payments;
option java_package = "org.bitcoin.protocols.payments";
option java_outer_classname = "Protos";
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index 20e1f79ffa..01ec416613 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -159,14 +159,24 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
std::string data_to_verify; // Everything but the signature
rcopy.SerializeToString(&data_to_verify);
- EVP_MD_CTX ctx;
+#if HAVE_DECL_EVP_MD_CTX_NEW
+ EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+ if (!ctx) throw SSLVerifyError("Error allocating OpenSSL context.");
+#else
+ EVP_MD_CTX _ctx;
+ EVP_MD_CTX *ctx;
+ ctx = &_ctx;
+#endif
EVP_PKEY *pubkey = X509_get_pubkey(signing_cert);
- EVP_MD_CTX_init(&ctx);
- if (!EVP_VerifyInit_ex(&ctx, digestAlgorithm, NULL) ||
- !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)) {
+ EVP_MD_CTX_init(ctx);
+ if (!EVP_VerifyInit_ex(ctx, digestAlgorithm, NULL) ||
+ !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.");
}
+#if HAVE_DECL_EVP_MD_CTX_NEW
+ EVP_MD_CTX_free(ctx);
+#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);
diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h
index a73fe5f29d..a2fea3fdc6 100644
--- a/src/qt/paymentrequestplus.h
+++ b/src/qt/paymentrequestplus.h
@@ -1,11 +1,14 @@
-// Copyright (c) 2011-2015 The Bitcoin developers
+// 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.
#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 c80aebb009..c31a7a478d 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -10,7 +10,7 @@
#include "base58.h"
#include "chainparams.h"
-#include "main.h" // For minRelayTxFee
+#include "policy/policy.h"
#include "ui_interface.h"
#include "util.h"
#include "wallet/wallet.h"
@@ -55,17 +55,20 @@ 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;
-X509_STORE* PaymentServer::certStore = NULL;
-void PaymentServer::freeCertStore()
+struct X509StoreDeleter {
+ void operator()(X509_STORE* b) {
+ X509_STORE_free(b);
+ }
+};
+
+struct X509Deleter {
+ void operator()(X509* b) { X509_free(b); }
+};
+
+namespace // Anon namespace
{
- if (PaymentServer::certStore != NULL)
- {
- X509_STORE_free(PaymentServer::certStore);
- PaymentServer::certStore = NULL;
- }
+ std::unique_ptr<X509_STORE, X509StoreDeleter> certStore;
}
//
@@ -80,7 +83,7 @@ static QString ipcServerName()
// Append a simple hash of the datadir
// Note that GetDataDir(true) returns a different path
// for -testnet versus main net
- QString ddir(QString::fromStdString(GetDataDir(true).string()));
+ QString ddir(GUIUtil::boostPathToQString(GetDataDir(true)));
name.append(QString::number(qHash(ddir)));
return name;
@@ -107,20 +110,15 @@ static void ReportInvalidCertificate(const QSslCertificate& cert)
//
void PaymentServer::LoadRootCAs(X509_STORE* _store)
{
- if (PaymentServer::certStore == NULL)
- atexit(PaymentServer::freeCertStore);
- else
- freeCertStore();
-
// Unit tests mostly use this, to pass in fake root CAs:
if (_store)
{
- PaymentServer::certStore = _store;
+ certStore.reset(_store);
return;
}
// Normal execution, use either -rootcertificates or system certs:
- PaymentServer::certStore = X509_STORE_new();
+ certStore.reset(X509_STORE_new());
// 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:
@@ -167,11 +165,11 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
QByteArray certData = cert.toDer();
const unsigned char *data = (const unsigned char *)certData.data();
- X509* x509 = d2i_X509(0, &data, certData.size());
- if (x509 && X509_STORE_add_cert(PaymentServer::certStore, x509))
+ std::unique_ptr<X509, X509Deleter> x509(d2i_X509(0, &data, certData.size()));
+ if (x509 && X509_STORE_add_cert(certStore.get(), x509.get()))
{
- // Note: X509_STORE_free will free the X509* objects when
- // the PaymentServer is destroyed
+ // Note: X509_STORE increases the reference count to the X509 object,
+ // we still have to release our reference to it.
++nRootCerts;
}
else
@@ -221,14 +219,16 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
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 (address.IsValid(*tempChainParams))
{
SelectParams(CBaseChainParams::MAIN);
}
- else if (address.IsValid(Params(CBaseChainParams::TESTNET)))
- {
- SelectParams(CBaseChainParams::TESTNET);
+ else {
+ tempChainParams = CreateChainParams(CBaseChainParams::TESTNET);
+ if (address.IsValid(*tempChainParams))
+ SelectParams(CBaseChainParams::TESTNET);
}
}
}
@@ -550,7 +550,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
recipient.paymentRequest = request;
recipient.message = GUIUtil::HtmlEscape(request.getDetails().memo());
- request.getMerchant(PaymentServer::certStore, recipient.authenticatedMerchant);
+ request.getMerchant(certStore.get(), recipient.authenticatedMerchant);
QList<std::pair<CScript, CAmount> > sendingTos = request.getPayTo();
QStringList addresses;
@@ -582,7 +582,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// Extract and check amounts
CTxOut txOut(sendingTo.second, sendingTo.first);
- if (txOut.IsDust(::minRelayTxFee)) {
+ 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);
@@ -749,9 +749,9 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError>
Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
}
-void PaymentServer::setOptionsModel(OptionsModel *optionsModel)
+void PaymentServer::setOptionsModel(OptionsModel *_optionsModel)
{
- this->optionsModel = optionsModel;
+ this->optionsModel = _optionsModel;
}
void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
@@ -807,3 +807,8 @@ bool PaymentServer::verifyAmount(const CAmount& requestAmount)
}
return fVerified;
}
+
+X509_STORE* PaymentServer::getCertStore()
+{
+ return certStore.get();
+}
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 2d27ed078b..7c6d4507fe 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -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
{
@@ -83,7 +83,7 @@ public:
static void LoadRootCAs(X509_STORE* store = NULL);
// Return certificate store
- static X509_STORE* getCertStore() { return certStore; }
+ static X509_STORE* getCertStore();
// OptionsModel is used for getting proxy settings and display unit
void setOptionsModel(OptionsModel *optionsModel);
@@ -140,9 +140,6 @@ private:
bool saveURIs; // true during startup
QLocalServer* uriServer;
- static X509_STORE* certStore; // Trusted root certificates
- static void freeCertStore();
-
QNetworkAccessManager* netManager; // Used to fetch payment requests
OptionsModel *optionsModel;
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 84ad0052fd..fff072fd4c 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -8,6 +8,7 @@
#include "guiconstants.h"
#include "guiutil.h"
+#include "validation.h" // for cs_main
#include "sync.h"
#include <QDebug>
@@ -24,12 +25,14 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine
switch(column)
{
+ case PeerTableModel::NetNodeId:
+ return pLeft->nodeid < pRight->nodeid;
case PeerTableModel::Address:
return pLeft->addrName.compare(pRight->addrName) < 0;
case PeerTableModel::Subversion:
return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
case PeerTableModel::Ping:
- return pLeft->dPingTime < pRight->dPingTime;
+ return pLeft->dMinPing < pRight->dMinPing;
}
return false;
@@ -52,24 +55,21 @@ public:
void refreshPeers()
{
{
- TRY_LOCK(cs_vNodes, lockNodes);
- if (!lockNodes)
- {
- // skip the refresh if we can't immediately get the lock
- return;
- }
cachedNodeStats.clear();
+ std::vector<CNodeStats> vstats;
+ if(g_connman)
+ g_connman->GetNodeStats(vstats);
#if QT_VERSION >= 0x040700
- cachedNodeStats.reserve(vNodes.size());
+ cachedNodeStats.reserve(vstats.size());
#endif
- Q_FOREACH (CNode* pnode, vNodes)
+ Q_FOREACH (const CNodeStats& nodestats, vstats)
{
CNodeCombinedStats stats;
stats.nodeStateStats.nMisbehavior = 0;
stats.nodeStateStats.nSyncHeight = -1;
stats.nodeStateStats.nCommonHeight = -1;
stats.fNodeStateStatsAvailable = false;
- pnode->copyStats(stats.nodeStats);
+ stats.nodeStats = nodestats;
cachedNodeStats.append(stats);
}
}
@@ -114,13 +114,13 @@ PeerTableModel::PeerTableModel(ClientModel *parent) :
clientModel(parent),
timer(0)
{
- columns << tr("Node/Service") << tr("User Agent") << tr("Ping Time");
- priv = new PeerTablePriv();
+ columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping");
+ priv.reset(new PeerTablePriv());
// default to unsorted
priv->sortColumn = -1;
// set up timer for auto refresh
- timer = new QTimer();
+ timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), SLOT(refresh()));
timer->setInterval(MODEL_UPDATE_DELAY);
@@ -128,6 +128,11 @@ PeerTableModel::PeerTableModel(ClientModel *parent) :
refresh();
}
+PeerTableModel::~PeerTableModel()
+{
+ // Intentionally left empty
+}
+
void PeerTableModel::startAutoRefresh()
{
timer->start();
@@ -160,12 +165,14 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
if (role == Qt::DisplayRole) {
switch(index.column())
{
+ case NetNodeId:
+ return (qint64)rec->nodeStats.nodeid;
case Address:
return QString::fromStdString(rec->nodeStats.addrName);
case Subversion:
return QString::fromStdString(rec->nodeStats.cleanSubVer);
case Ping:
- return GUIUtil::formatPingTime(rec->nodeStats.dPingTime);
+ return GUIUtil::formatPingTime(rec->nodeStats.dMinPing);
}
} else if (role == Qt::TextAlignmentRole) {
if (index.column() == Ping)
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index a2aaaa5d24..cc47b67ec9 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
#ifndef BITCOIN_QT_PEERTABLEMODEL_H
#define BITCOIN_QT_PEERTABLEMODEL_H
-#include "main.h" // For CNodeStateStats
+#include "net_processing.h" // For CNodeStateStats
#include "net.h"
#include <QAbstractTableModel>
@@ -46,15 +46,17 @@ class PeerTableModel : public QAbstractTableModel
public:
explicit PeerTableModel(ClientModel *parent = 0);
+ ~PeerTableModel();
const CNodeCombinedStats *getNodeStats(int idx);
int getRowByNodeId(NodeId nodeid);
void startAutoRefresh();
void stopAutoRefresh();
enum ColumnIndex {
- Address = 0,
- Subversion = 1,
- Ping = 2
+ NetNodeId = 0,
+ Address = 1,
+ Subversion = 2,
+ Ping = 3
};
/** @name Methods overridden from QAbstractTableModel
@@ -74,7 +76,7 @@ public Q_SLOTS:
private:
ClientModel *clientModel;
QStringList columns;
- PeerTablePriv *priv;
+ std::unique_ptr<PeerTablePriv> priv;
QTimer *timer;
};
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index 11cbc7a47c..90bd619c04 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -73,11 +73,11 @@ QIcon ColorizeIcon(const QString& filename, const QColor& colorbase)
}
-PlatformStyle::PlatformStyle(const QString &name, bool imagesOnButtons, bool colorizeIcons, bool useExtraSpacing):
- name(name),
- imagesOnButtons(imagesOnButtons),
- colorizeIcons(colorizeIcons),
- useExtraSpacing(useExtraSpacing),
+PlatformStyle::PlatformStyle(const QString &_name, bool _imagesOnButtons, bool _colorizeIcons, bool _useExtraSpacing):
+ name(_name),
+ imagesOnButtons(_imagesOnButtons),
+ colorizeIcons(_colorizeIcons),
+ useExtraSpacing(_useExtraSpacing),
singleColor(0,0,0),
textColor(0,0,0)
{
diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp
index baa2eb67f7..179ecdc8b3 100644
--- a/src/qt/qvalidatedlineedit.cpp
+++ b/src/qt/qvalidatedlineedit.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -15,14 +15,14 @@ QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) :
connect(this, SIGNAL(textChanged(QString)), this, SLOT(markValid()));
}
-void QValidatedLineEdit::setValid(bool valid)
+void QValidatedLineEdit::setValid(bool _valid)
{
- if(valid == this->valid)
+ if(_valid == this->valid)
{
return;
}
- if(valid)
+ if(_valid)
{
setStyleSheet("");
}
@@ -30,7 +30,7 @@ void QValidatedLineEdit::setValid(bool valid)
{
setStyleSheet(STYLE_INVALID);
}
- this->valid = valid;
+ this->valid = _valid;
}
void QValidatedLineEdit::focusInEvent(QFocusEvent *evt)
diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp
index 146f3dd578..a3b9b994ec 100644
--- a/src/qt/qvaluecombobox.cpp
+++ b/src/qt/qvaluecombobox.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -20,9 +20,9 @@ void QValueComboBox::setValue(const QVariant &value)
setCurrentIndex(findData(value, role));
}
-void QValueComboBox::setRole(int role)
+void QValueComboBox::setRole(int _role)
{
- this->role = role;
+ this->role = _role;
}
void QValueComboBox::handleSelectionChanged(int idx)
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 0b355837ab..e98f4d3347 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -22,39 +22,43 @@
#include <QScrollBar>
#include <QTextDocument>
-ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
+ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::ReceiveCoinsDialog),
+ columnResizingFixer(0),
model(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
ui->setupUi(this);
- if (!platformStyle->getImagesOnButtons()) {
+ if (!_platformStyle->getImagesOnButtons()) {
ui->clearButton->setIcon(QIcon());
ui->receiveButton->setIcon(QIcon());
ui->showRequestButton->setIcon(QIcon());
ui->removeRequestButton->setIcon(QIcon());
} else {
- ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
- ui->receiveButton->setIcon(platformStyle->SingleColorIcon(":/icons/receiving_addresses"));
- ui->showRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/edit"));
- ui->removeRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->receiveButton->setIcon(_platformStyle->SingleColorIcon(":/icons/receiving_addresses"));
+ ui->showRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/edit"));
+ ui->removeRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
}
// context menu actions
+ QAction *copyURIAction = new QAction(tr("Copy URI"), this);
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
QAction *copyMessageAction = new QAction(tr("Copy message"), this);
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
// context menu
- contextMenu = new QMenu();
+ contextMenu = new QMenu(this);
+ contextMenu->addAction(copyURIAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(copyMessageAction);
contextMenu->addAction(copyAmountAction);
// context menu signals
connect(ui->recentRequestsView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
+ connect(copyURIAction, SIGNAL(triggered()), this, SLOT(copyURI()));
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
@@ -62,21 +66,21 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidg
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
}
-void ReceiveCoinsDialog::setModel(WalletModel *model)
+void ReceiveCoinsDialog::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
- if(model && model->getOptionsModel())
+ if(_model && _model->getOptionsModel())
{
- model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
- connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
+ _model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
+ connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
updateDisplayUnit();
QTableView* tableView = ui->recentRequestsView;
tableView->verticalHeader()->hide();
tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- tableView->setModel(model->getRecentRequestsTableModel());
+ tableView->setModel(_model->getRecentRequestsTableModel());
tableView->setAlternatingRowColors(true);
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
@@ -88,7 +92,7 @@ void ReceiveCoinsDialog::setModel(WalletModel *model)
SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this,
SLOT(recentRequestsView_selectionChanged(QItemSelection, QItemSelection)));
// Last 2 columns are set by the columnResizingFixer, when the table geometry is ready.
- columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH);
+ columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);
}
}
@@ -228,30 +232,50 @@ void ReceiveCoinsDialog::keyPressEvent(QKeyEvent *event)
this->QDialog::keyPressEvent(event);
}
-// copy column of selected row to clipboard
-void ReceiveCoinsDialog::copyColumnToClipboard(int column)
+QModelIndex ReceiveCoinsDialog::selectedRow()
{
if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
- return;
+ return QModelIndex();
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
if(selection.empty())
- return;
+ return QModelIndex();
// correct for selection mode ContiguousSelection
QModelIndex firstIndex = selection.at(0);
+ return firstIndex;
+}
+
+// copy column of selected row to clipboard
+void ReceiveCoinsDialog::copyColumnToClipboard(int column)
+{
+ QModelIndex firstIndex = selectedRow();
+ if (!firstIndex.isValid()) {
+ return;
+ }
GUIUtil::setClipboard(model->getRecentRequestsTableModel()->data(firstIndex.child(firstIndex.row(), column), Qt::EditRole).toString());
}
// context menu
void ReceiveCoinsDialog::showMenu(const QPoint &point)
{
- if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
- return;
- QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
- if(selection.empty())
+ if (!selectedRow().isValid()) {
return;
+ }
contextMenu->exec(QCursor::pos());
}
+// context menu action: copy URI
+void ReceiveCoinsDialog::copyURI()
+{
+ QModelIndex sel = selectedRow();
+ if (!sel.isValid()) {
+ return;
+ }
+
+ const RecentRequestsTableModel * const submodel = model->getRecentRequestsTableModel();
+ const QString uri = GUIUtil::formatBitcoinURI(submodel->entry(sel.row()).recipient);
+ GUIUtil::setClipboard(uri);
+}
+
// context menu action: copy label
void ReceiveCoinsDialog::copyLabel()
{
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index 226fd65cfa..1d0491c0d5 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -60,6 +60,7 @@ private:
QMenu *contextMenu;
const PlatformStyle *platformStyle;
+ QModelIndex selectedRow();
void copyColumnToClipboard(int column);
virtual void resizeEvent(QResizeEvent *event);
@@ -71,6 +72,7 @@ private Q_SLOTS:
void recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void updateDisplayUnit();
void showMenu(const QPoint &point);
+ void copyURI();
void copyLabel();
void copyMessage();
void copyAmount();
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index b13ea3df70..3752fa4b66 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -32,7 +32,7 @@
QRImageWidget::QRImageWidget(QWidget *parent):
QLabel(parent), contextMenu(0)
{
- contextMenu = new QMenu();
+ contextMenu = new QMenu(this);
QAction *saveImageAction = new QAction(tr("&Save Image..."), this);
connect(saveImageAction, SIGNAL(triggered()), this, SLOT(saveImage()));
contextMenu->addAction(saveImageAction);
@@ -109,20 +109,20 @@ ReceiveRequestDialog::~ReceiveRequestDialog()
delete ui;
}
-void ReceiveRequestDialog::setModel(OptionsModel *model)
+void ReceiveRequestDialog::setModel(OptionsModel *_model)
{
- this->model = model;
+ this->model = _model;
- if (model)
- connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(update()));
+ if (_model)
+ connect(_model, SIGNAL(displayUnitChanged(int)), this, SLOT(update()));
// update the display unit if necessary
update();
}
-void ReceiveRequestDialog::setInfo(const SendCoinsRecipient &info)
+void ReceiveRequestDialog::setInfo(const SendCoinsRecipient &_info)
{
- this->info = info;
+ this->info = _info;
update();
}
diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h
index 676745a858..1a9b165237 100644
--- a/src/qt/receiverequestdialog.h
+++ b/src/qt/receiverequestdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 2335d6b282..dac3979290 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -14,7 +14,7 @@
#include <boost/foreach.hpp>
RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel *parent) :
- walletModel(parent)
+ QAbstractTableModel(parent), walletModel(parent)
{
Q_UNUSED(wallet);
nReceiveRequestsMaxId = 0;
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index f3cf03f4e3..0c02968f92 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -27,11 +27,10 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
unsigned int nDate = date.toTime_t();
READWRITE(this->nVersion);
- nVersion = this->nVersion;
READWRITE(id);
READWRITE(nDate);
READWRITE(recipient);
diff --git a/src/qt/res/icons/hd_disabled.png b/src/qt/res/icons/hd_disabled.png
new file mode 100644
index 0000000000..687b6d2e38
--- /dev/null
+++ b/src/qt/res/icons/hd_disabled.png
Binary files differ
diff --git a/src/qt/res/icons/hd_enabled.png b/src/qt/res/icons/hd_enabled.png
new file mode 100644
index 0000000000..568dde1cd1
--- /dev/null
+++ b/src/qt/res/icons/hd_enabled.png
Binary files differ
diff --git a/src/qt/res/icons/network_disabled.png b/src/qt/res/icons/network_disabled.png
new file mode 100644
index 0000000000..269c3cfab8
--- /dev/null
+++ b/src/qt/res/icons/network_disabled.png
Binary files differ
diff --git a/src/qt/res/movies/makespinner.sh b/src/qt/res/movies/makespinner.sh
index a4c2fddbbf..d0deb1238c 100755
--- a/src/qt/res/movies/makespinner.sh
+++ b/src/qt/res/movies/makespinner.sh
@@ -1,3 +1,7 @@
+# Copyright (c) 2014-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.
+
FRAMEDIR=$(dirname $0)
for i in {0..35}
do
diff --git a/src/qt/res/src/connect-0.svg b/src/qt/res/src/connect-0.svg
index 7d2afac622..0920555b96 100644
--- a/src/qt/res/src/connect-0.svg
+++ b/src/qt/res/src/connect-0.svg
@@ -7,8 +7,8 @@
xmlns="http://www.w3.org/2000/svg"
id="svg2"
viewBox="0 0 24 24"
- height="24"
- width="24"
+ height="92"
+ width="92"
version="1.2">
<metadata
id="metadata10">
diff --git a/src/qt/res/src/connect-1.svg b/src/qt/res/src/connect-1.svg
index d17928c97d..25dea4cd3a 100644
--- a/src/qt/res/src/connect-1.svg
+++ b/src/qt/res/src/connect-1.svg
@@ -6,8 +6,8 @@
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.2"
- width="24"
- height="24"
+ width="92"
+ height="92"
viewBox="0 0 24 24"
id="svg2">
<metadata
diff --git a/src/qt/res/src/connect-2.svg b/src/qt/res/src/connect-2.svg
index 841ca6071d..bb98333d23 100644
--- a/src/qt/res/src/connect-2.svg
+++ b/src/qt/res/src/connect-2.svg
@@ -6,8 +6,8 @@
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.2"
- width="24"
- height="24"
+ width="92"
+ height="92"
viewBox="0 0 24 24"
id="svg2">
<metadata
diff --git a/src/qt/res/src/connect-3.svg b/src/qt/res/src/connect-3.svg
index b06e67daf8..a54a55ef61 100644
--- a/src/qt/res/src/connect-3.svg
+++ b/src/qt/res/src/connect-3.svg
@@ -7,8 +7,8 @@
xmlns="http://www.w3.org/2000/svg"
id="svg2"
viewBox="0 0 24 24"
- height="24"
- width="24"
+ height="92"
+ width="92"
version="1.2">
<metadata
id="metadata10">
diff --git a/src/qt/res/src/connect-4.svg b/src/qt/res/src/connect-4.svg
index 0abc7955fd..b83b9f9d03 100644
--- a/src/qt/res/src/connect-4.svg
+++ b/src/qt/res/src/connect-4.svg
@@ -6,8 +6,8 @@
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.2"
- width="24"
- height="24"
+ width="92"
+ height="92"
viewBox="0 0 24 24"
id="svg2">
<metadata
diff --git a/src/qt/res/src/hd_disabled.svg b/src/qt/res/src/hd_disabled.svg
new file mode 100644
index 0000000000..035f4431c7
--- /dev/null
+++ b/src/qt/res/src/hd_disabled.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 595.3 841.9" enable-background="new 0 0 595.3 841.9" xml:space="preserve">
+<g>
+ <path d="M81.3,336.5v66.8h70.4v-66.8H190v174h-38.3v-75.1H81.3v75.1H43v-174H81.3z"/>
+ <path d="M298.7,336.5c11.2,0,21.6,1.8,31.3,5.4c9.7,3.6,18,8.9,25.1,16.1c7.1,7.2,12.6,16.1,16.6,26.8c4,10.7,6,23.3,6,37.8
+ c0,12.7-1.6,24.4-4.9,35.1c-3.3,10.7-8.2,20-14.7,27.8c-6.6,7.8-14.8,13.9-24.6,18.4c-9.8,4.5-21.4,6.7-34.7,6.7h-75.1v-174H298.7z
+ M296,478.3c5.5,0,10.9-0.9,16.1-2.7c5.2-1.8,9.8-4.8,13.9-8.9c4.1-4.1,7.3-9.5,9.7-16.2c2.4-6.7,3.7-14.8,3.7-24.4
+ c0-8.8-0.9-16.7-2.6-23.8s-4.5-13.1-8.4-18.2c-3.9-5-9.1-8.9-15.5-11.6c-6.4-2.7-14.3-4-23.8-4h-27.3v109.7H296z"/>
+</g>
+<g>
+ <g>
+ <line x1="32" y1="555.9" x2="358" y2="293.9"/>
+ </g>
+ <g>
+ <path fill="#FFFFFF" d="M32,580.9c-7.3,0-14.6-3.2-19.5-9.3c-8.6-10.8-6.9-26.5,3.8-35.1l326-262c10.8-8.6,26.5-6.9,35.1,3.8
+ c8.6,10.8,6.9,26.5-3.8,35.1l-326,262C43,579.1,37.5,580.9,32,580.9z"/>
+ </g>
+ <g>
+ <path d="M32,573.9c-5.3,0-10.5-2.3-14-6.7c-6.2-7.7-5-19.1,2.8-25.3l326-262c7.8-6.2,19.1-5,25.3,2.8c6.2,7.7,5,19.1-2.8,25.3
+ l-326,262C40,572.6,36,573.9,32,573.9z"/>
+ </g>
+</g>
+</svg>
diff --git a/src/qt/res/src/hd_enabled.svg b/src/qt/res/src/hd_enabled.svg
new file mode 100644
index 0000000000..cbaa16f8f0
--- /dev/null
+++ b/src/qt/res/src/hd_enabled.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 595.3 841.9" enable-background="new 0 0 595.3 841.9" xml:space="preserve">
+<g>
+ <path d="M81.3,336.5v66.8h70.4v-66.8H190v174h-38.3v-75.1H81.3v75.1H43v-174H81.3z"/>
+ <path d="M298.7,336.5c11.2,0,21.6,1.8,31.3,5.4c9.7,3.6,18,8.9,25.1,16.1c7.1,7.2,12.6,16.1,16.6,26.8c4,10.7,6,23.3,6,37.8
+ c0,12.7-1.6,24.4-4.9,35.1c-3.3,10.7-8.2,20-14.7,27.8c-6.6,7.8-14.8,13.9-24.6,18.4c-9.8,4.5-21.4,6.7-34.7,6.7h-75.1v-174H298.7z
+ M296,478.3c5.5,0,10.9-0.9,16.1-2.7c5.2-1.8,9.8-4.8,13.9-8.9c4.1-4.1,7.3-9.5,9.7-16.2c2.4-6.7,3.7-14.8,3.7-24.4
+ c0-8.8-0.9-16.7-2.6-23.8s-4.5-13.1-8.4-18.2c-3.9-5-9.1-8.9-15.5-11.6c-6.4-2.7-14.3-4-23.8-4h-27.3v109.7H296z"/>
+</g>
+</svg>
diff --git a/src/qt/res/src/network_disabled.svg b/src/qt/res/src/network_disabled.svg
new file mode 100644
index 0000000000..a041d77439
--- /dev/null
+++ b/src/qt/res/src/network_disabled.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ id="svg2"
+ viewBox="0 0 24 24"
+ width="92"
+ height="92"
+ version="1.2">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <g
+ id="g4142"
+ transform="matrix(0,-1,-1,0,23.96,24)">
+ <g
+ id="g4210"
+ transform="matrix(-1,0,0,1,59.86,-106.6)">
+ <g
+ id="g4289"
+ transform="matrix(-1,0,0,1,-16.98,0.8136)">
+ <g
+ id="g4291">
+ <path
+ id="path4293"
+ transform="matrix(0,-1,-1,0,-52.84,129.7464)"
+ d="M 20.146484 1.0097656 C 18.746484 1.0097656 17.646484 1.8597656 17.146484 3.0097656 L 14.447266 3.0097656 C 12.247266 3.0097656 10.447266 4.7997656 10.447266 7.0097656 L 10.447266 8.1425781 C 10.128283 8.0634395 9.7980674 8.0097656 9.4472656 8.0097656 L 6.8457031 8.0097656 C 6.3457031 6.8597656 5.2457031 6.0097656 3.8457031 6.0097656 C 1.8457031 6.0097656 0.34570312 7.5997656 0.34570312 9.5097656 C 0.34570312 11.419766 1.8457031 13.009766 3.8457031 13.009766 C 5.2457031 13.009766 6.3457031 12.159766 6.8457031 11.009766 L 8.9746094 11.009766 C 8.8693536 11.330059 8.8007812 11.663345 8.8007812 12.001953 C 8.8007813 12.841953 9.1402344 13.671625 9.7402344 14.265625 C 9.9479364 14.475439 10.191281 14.640988 10.447266 14.783203 L 10.447266 16.980469 C 10.447266 17.530469 9.9472656 17.980469 9.4472656 17.980469 L 6.8457031 17.980469 C 6.3457031 16.830469 5.2457031 15.980469 3.8457031 15.980469 C 1.8457031 15.980469 0.34570312 17.570469 0.34570312 19.480469 C 0.34570312 21.390469 1.8457031 22.990234 3.8457031 22.990234 C 5.2457031 22.990234 6.2457031 22.14 6.8457031 21 L 9.4472656 21 C 11.747266 21 13.447266 19.19 13.447266 17 L 13.447266 15.869141 C 13.768504 15.952624 14.100702 16.009766 14.447266 16.009766 L 17.146484 16.009766 C 17.646484 17.159766 18.746484 18.009766 20.146484 18.009766 C 22.046484 18.009766 23.646484 16.449766 23.646484 14.509766 C 23.646484 12.579766 22.046484 11.009766 20.146484 11.009766 C 18.746484 11.009766 17.646484 11.859766 17.146484 13.009766 L 15.009766 13.009766 C 15.119625 12.684735 15.189453 12.346256 15.189453 12 C 15.189453 11.16 14.849906 10.339953 14.253906 9.7519531 C 14.0189 9.51021 13.74069 9.3244522 13.447266 9.171875 L 13.447266 7.0097656 C 13.447266 6.4597656 13.947266 6.0097656 14.447266 6.0097656 L 17.146484 6.0097656 C 17.646484 7.1597656 18.746484 8.0097656 20.146484 8.0097656 C 22.046484 8.0097656 23.646484 6.4397656 23.646484 4.5097656 C 23.646484 2.5697656 22.046484 1.0097656 20.146484 1.0097656 z M 20.146484 2.0097656 C 21.446484 2.0097656 22.646484 3.1297656 22.646484 4.5097656 C 22.646484 5.8797656 21.446484 7.0097656 20.146484 7.0097656 C 19.046484 7.0097656 18.145703 6.3096094 17.845703 5.3496094 L 17.746094 5.0097656 L 14.447266 5.0097656 C 13.347266 5.0097656 12.447266 5.8997656 12.447266 7.0097656 L 12.447266 8.8476562 C 12.298996 8.8261586 12.150754 8.8027344 12 8.8027344 C 11.954455 8.8027344 11.910576 8.8144662 11.865234 8.8164062 C 11.733157 8.716719 11.592447 8.6297054 11.447266 8.546875 L 11.447266 7.0097656 C 11.447266 5.3597656 12.847266 4.0097656 14.447266 4.0097656 L 17.746094 4.0097656 L 17.845703 3.6699219 C 18.145703 2.7099219 19.046484 2.0097656 20.146484 2.0097656 z M 3.8457031 7.0097656 C 4.9457031 7.0097656 5.8464844 7.7099219 6.1464844 8.6699219 L 6.2460938 9.0097656 L 9.4472656 9.0097656 C 9.8222656 9.0097656 10.165234 9.0792969 10.474609 9.2050781 C 10.207952 9.3508551 9.9554097 9.5233651 9.7402344 9.7421875 C 9.6554755 9.8255337 9.5878282 9.9233484 9.5136719 10.015625 C 9.4909069 10.014746 9.470428 10.009766 9.4472656 10.009766 L 6.2460938 10.009766 L 6.1464844 10.349609 C 5.8464844 11.319609 4.9457031 12.009766 3.8457031 12.009766 C 2.4457031 12.009766 1.3457031 10.899766 1.3457031 9.5097656 C 1.3457031 8.1197656 2.4457031 7.0097656 3.8457031 7.0097656 z M 20.146484 12.009766 C 21.446484 12.009766 22.646484 13.139766 22.646484 14.509766 C 22.646484 15.889766 21.446484 17.009766 20.146484 17.009766 C 19.046484 17.009766 18.145703 16.309609 17.845703 15.349609 L 17.746094 15.009766 L 14.447266 15.009766 C 14.100959 15.009766 13.772729 14.94045 13.470703 14.816406 C 13.754756 14.666178 14.02454 14.485593 14.253906 14.253906 C 14.328913 14.179151 14.386367 14.091269 14.453125 14.009766 L 17.746094 14.009766 L 17.845703 13.669922 C 18.145703 12.709922 19.046484 12.009766 20.146484 12.009766 z M 11.447266 15.144531 C 11.629002 15.17624 11.813246 15.199219 12 15.199219 C 12.018544 15.199153 12.036184 15.193748 12.054688 15.193359 C 12.180437 15.288088 12.3107 15.373496 12.447266 15.453125 L 12.447266 17 C 12.447266 18.67 11.147266 20 9.4472656 20 L 6.6464844 20 L 6.2460938 20 L 6.1464844 20.330078 C 5.8464844 21.290078 4.9457031 21.990234 3.8457031 21.990234 C 2.4457031 21.990234 1.3457031 20.870469 1.3457031 19.480469 C 1.3457031 18.090469 2.4457031 16.980469 3.8457031 16.980469 C 4.9457031 16.980469 5.8464844 17.680625 6.1464844 18.640625 L 6.2460938 18.980469 L 9.4472656 18.980469 C 10.547266 18.980469 11.447266 18.090469 11.447266 16.980469 L 11.447266 15.144531 z "
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.5;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <path d="M 3,3 l 18,18" style="stroke-width: 3; stroke: #000000; stroke-linecap: round;" />
+ <path d="M 21,3 l -18,18" style="stroke-width: 3; stroke: #000000; stroke-linecap: round;" />
+</svg>
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 650ff8b00d..2ff78c75cb 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -16,6 +16,7 @@
#include "bantablemodel.h"
#include "chainparams.h"
+#include "netbase.h"
#include "rpc/server.h"
#include "rpc/client.h"
#include "util.h"
@@ -30,6 +31,7 @@
#include <QKeyEvent>
#include <QMenu>
+#include <QMessageBox>
#include <QScrollBar>
#include <QSettings>
#include <QSignalMapper>
@@ -62,6 +64,20 @@ const struct {
{NULL, NULL}
};
+namespace {
+
+// don't add private key handling cmd's to the history
+const QStringList historyFilter = QStringList()
+ << "importprivkey"
+ << "importmulti"
+ << "signmessagewithprivkey"
+ << "signrawtransaction"
+ << "walletpassphrase"
+ << "walletpassphrasechange"
+ << "encryptwallet";
+
+}
+
/* Object for executing console RPC commands in a separate thread.
*/
class RPCExecutor : public QObject
@@ -82,8 +98,8 @@ class QtRPCTimerBase: public QObject, public RPCTimerBase
{
Q_OBJECT
public:
- QtRPCTimerBase(boost::function<void(void)>& func, int64_t millis):
- func(func)
+ QtRPCTimerBase(boost::function<void(void)>& _func, int64_t millis):
+ func(_func)
{
timer.setSingleShot(true);
connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
@@ -112,9 +128,11 @@ public:
#include "rpcconsole.moc"
/**
- * Split shell command line into a list of arguments. Aims to emulate \c bash and friends.
+ * Split shell command line into a list of arguments and optionally execute the command(s).
+ * Aims to emulate \c bash and friends.
*
- * - Arguments are delimited with whitespace
+ * - Command nesting is possible with parenthesis; for example: validateaddress(getnewaddress())
+ * - Arguments are delimited with whitespace or comma
* - Extra whitespace at the beginning and end and between arguments will be ignored
* - Text can be "double" or 'single' quoted
* - The backslash \c \ is used as escape character
@@ -122,107 +140,256 @@ public:
* - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
* - Within single quotes, no escaping is possible and no special interpretation takes place
*
- * @param[out] args Parsed arguments will be appended to this list
+ * @param[out] result stringified Result from the executed command(chain)
* @param[in] strCommand Command line to split
+ * @param[in] fExecute set true if you want the command to be executed
+ * @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data
*/
-bool parseCommandLine(std::vector<std::string> &args, const std::string &strCommand)
+
+bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut)
{
+ std::vector< std::vector<std::string> > stack;
+ stack.push_back(std::vector<std::string>());
+
enum CmdParseState
{
STATE_EATING_SPACES,
+ STATE_EATING_SPACES_IN_ARG,
+ STATE_EATING_SPACES_IN_BRACKETS,
STATE_ARGUMENT,
STATE_SINGLEQUOTED,
STATE_DOUBLEQUOTED,
STATE_ESCAPE_OUTER,
- STATE_ESCAPE_DOUBLEQUOTED
+ STATE_ESCAPE_DOUBLEQUOTED,
+ STATE_COMMAND_EXECUTED,
+ STATE_COMMAND_EXECUTED_INNER
} state = STATE_EATING_SPACES;
std::string curarg;
- Q_FOREACH(char ch, strCommand)
+ UniValue lastResult;
+ unsigned nDepthInsideSensitive = 0;
+ size_t filter_begin_pos = 0, chpos;
+ std::vector<std::pair<size_t, size_t>> filter_ranges;
+
+ auto add_to_current_stack = [&](const std::string& strArg) {
+ if (stack.back().empty() && (!nDepthInsideSensitive) && historyFilter.contains(QString::fromStdString(strArg), Qt::CaseInsensitive)) {
+ 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);
+ };
+
+ auto close_out_params = [&]() {
+ if (nDepthInsideSensitive) {
+ if (!--nDepthInsideSensitive) {
+ assert(filter_begin_pos);
+ filter_ranges.push_back(std::make_pair(filter_begin_pos, chpos));
+ filter_begin_pos = 0;
+ }
+ }
+ stack.pop_back();
+ };
+
+ std::string strCommandTerminated = strCommand;
+ if (strCommandTerminated.back() != '\n')
+ strCommandTerminated += "\n";
+ for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos)
{
+ char ch = strCommandTerminated[chpos];
switch(state)
{
- case STATE_ARGUMENT: // In or after argument
- case STATE_EATING_SPACES: // Handle runs of whitespace
- switch(ch)
+ case STATE_COMMAND_EXECUTED_INNER:
+ case STATE_COMMAND_EXECUTED:
{
- case '"': state = STATE_DOUBLEQUOTED; break;
- case '\'': state = STATE_SINGLEQUOTED; break;
- case '\\': state = STATE_ESCAPE_OUTER; break;
- case ' ': case '\n': case '\t':
- if(state == STATE_ARGUMENT) // Space ends argument
+ bool breakParsing = true;
+ switch(ch)
{
- args.push_back(curarg);
- curarg.clear();
+ case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break;
+ default:
+ if (state == STATE_COMMAND_EXECUTED_INNER)
+ {
+ if (ch != ']')
+ {
+ // append char to the current argument (which is also used for the query command)
+ curarg += ch;
+ break;
+ }
+ if (curarg.size() && fExecute)
+ {
+ // if we have a value query, query arrays with index and objects with a string key
+ UniValue subelement;
+ if (lastResult.isArray())
+ {
+ for(char argch: curarg)
+ if (!std::isdigit(argch))
+ throw std::runtime_error("Invalid result query");
+ subelement = lastResult[atoi(curarg.c_str())];
+ }
+ else if (lastResult.isObject())
+ subelement = find_value(lastResult, curarg);
+ else
+ throw std::runtime_error("Invalid result query"); //no array or object: abort
+ lastResult = subelement;
+ }
+
+ state = STATE_COMMAND_EXECUTED;
+ break;
+ }
+ // don't break parsing when the char is required for the next argument
+ breakParsing = false;
+
+ // pop the stack and return the result to the current command arguments
+ close_out_params();
+
+ // don't stringify the json in case of a string to avoid doublequotes
+ if (lastResult.isStr())
+ curarg = lastResult.get_str();
+ else
+ curarg = lastResult.write(2);
+
+ // if we have a non empty result, use it as stack argument otherwise as general result
+ if (curarg.size())
+ {
+ if (stack.size())
+ add_to_current_stack(curarg);
+ else
+ strResult = curarg;
+ }
+ curarg.clear();
+ // assume eating space state
+ state = STATE_EATING_SPACES;
}
- state = STATE_EATING_SPACES;
- break;
- default: curarg += ch; state = STATE_ARGUMENT;
+ if (breakParsing)
+ break;
}
- break;
- case STATE_SINGLEQUOTED: // Single-quoted string
- switch(ch)
+ case STATE_ARGUMENT: // In or after argument
+ case STATE_EATING_SPACES_IN_ARG:
+ case STATE_EATING_SPACES_IN_BRACKETS:
+ case STATE_EATING_SPACES: // Handle runs of whitespace
+ switch(ch)
{
- case '\'': state = STATE_ARGUMENT; break;
- default: curarg += ch;
+ case '"': state = STATE_DOUBLEQUOTED; break;
+ case '\'': state = STATE_SINGLEQUOTED; break;
+ case '\\': state = STATE_ESCAPE_OUTER; break;
+ case '(': case ')': case '\n':
+ if (state == STATE_EATING_SPACES_IN_ARG)
+ throw std::runtime_error("Invalid Syntax");
+ if (state == STATE_ARGUMENT)
+ {
+ if (ch == '(' && stack.size() && stack.back().size() > 0)
+ {
+ if (nDepthInsideSensitive) {
+ ++nDepthInsideSensitive;
+ }
+ stack.push_back(std::vector<std::string>());
+ }
+
+ // don't allow commands after executed commands on baselevel
+ if (!stack.size())
+ throw std::runtime_error("Invalid Syntax");
+
+ add_to_current_stack(curarg);
+ curarg.clear();
+ state = STATE_EATING_SPACES_IN_BRACKETS;
+ }
+ if ((ch == ')' || ch == '\n') && stack.size() > 0)
+ {
+ if (fExecute) {
+ // Convert argument list to JSON objects in method-dependent way,
+ // and pass it along with the method name to the dispatcher.
+ JSONRPCRequest req;
+ req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
+ req.strMethod = stack.back()[0];
+ lastResult = tableRPC.execute(req);
+ }
+
+ state = STATE_COMMAND_EXECUTED;
+ curarg.clear();
+ }
+ break;
+ case ' ': case ',': case '\t':
+ if(state == STATE_EATING_SPACES_IN_ARG && curarg.empty() && ch == ',')
+ throw std::runtime_error("Invalid Syntax");
+
+ else if(state == STATE_ARGUMENT) // Space ends argument
+ {
+ add_to_current_stack(curarg);
+ curarg.clear();
+ }
+ if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',')
+ {
+ state = STATE_EATING_SPACES_IN_ARG;
+ break;
+ }
+ state = STATE_EATING_SPACES;
+ break;
+ default: curarg += ch; state = STATE_ARGUMENT;
}
- break;
- case STATE_DOUBLEQUOTED: // Double-quoted string
- switch(ch)
+ break;
+ case STATE_SINGLEQUOTED: // Single-quoted string
+ switch(ch)
{
- case '"': state = STATE_ARGUMENT; break;
- case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
- default: curarg += ch;
+ case '\'': state = STATE_ARGUMENT; break;
+ default: curarg += ch;
}
- break;
- case STATE_ESCAPE_OUTER: // '\' outside quotes
- curarg += ch; state = STATE_ARGUMENT;
- break;
- case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
- if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
- curarg += ch; state = STATE_DOUBLEQUOTED;
- break;
+ break;
+ case STATE_DOUBLEQUOTED: // Double-quoted string
+ switch(ch)
+ {
+ case '"': state = STATE_ARGUMENT; break;
+ case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
+ default: curarg += ch;
+ }
+ break;
+ case STATE_ESCAPE_OUTER: // '\' outside quotes
+ curarg += ch; state = STATE_ARGUMENT;
+ break;
+ case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
+ if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
+ curarg += ch; state = STATE_DOUBLEQUOTED;
+ break;
+ }
+ }
+ if (pstrFilteredOut) {
+ if (STATE_COMMAND_EXECUTED == state) {
+ assert(!stack.empty());
+ close_out_params();
+ }
+ *pstrFilteredOut = strCommand;
+ for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {
+ pstrFilteredOut->replace(i->first, i->second - i->first, "(…)");
}
}
switch(state) // final state
{
- case STATE_EATING_SPACES:
- return true;
- case STATE_ARGUMENT:
- args.push_back(curarg);
- return true;
- default: // ERROR to end in one of the other states
- return false;
+ case STATE_COMMAND_EXECUTED:
+ if (lastResult.isStr())
+ strResult = lastResult.get_str();
+ else
+ strResult = lastResult.write(2);
+ case STATE_ARGUMENT:
+ case STATE_EATING_SPACES:
+ return true;
+ default: // ERROR to end in one of the other states
+ return false;
}
}
void RPCExecutor::request(const QString &command)
{
- std::vector<std::string> args;
- if(!parseCommandLine(args, command.toStdString()))
- {
- Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
- return;
- }
- if(args.empty())
- return; // Nothing to do
try
{
- std::string strPrint;
- // Convert argument list to JSON objects in method-dependent way,
- // and pass it along with the method name to the dispatcher.
- UniValue result = tableRPC.execute(
- args[0],
- RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));
-
- // Format result reply
- if (result.isNull())
- strPrint = "";
- else if (result.isStr())
- strPrint = result.get_str();
- else
- strPrint = result.write(2);
-
- Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
+ std::string result;
+ std::string executableCommand = command.toStdString() + "\n";
+ if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand))
+ {
+ Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
+ return;
+ }
+ Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result));
}
catch (UniValue& objError)
{
@@ -243,13 +410,12 @@ void RPCExecutor::request(const QString &command)
}
}
-RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
+RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
QWidget(parent),
ui(new Ui::RPCConsole),
clientModel(0),
historyPtr(0),
- cachedNodeid(-1),
- platformStyle(platformStyle),
+ platformStyle(_platformStyle),
peersTableContextMenu(0),
banTableContextMenu(0),
consoleFontSize(0)
@@ -288,7 +454,6 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
// based timer interface
RPCSetTimerInterfaceIfUnset(rpcTimerInterface);
- startExecutor();
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
ui->detailWidget->hide();
@@ -302,7 +467,6 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
RPCConsole::~RPCConsole()
{
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
- Q_EMIT stopExecutor();
RPCUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
@@ -364,6 +528,9 @@ void RPCConsole::setClientModel(ClientModel *model)
setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL), false);
connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
+ updateNetworkState();
+ connect(model, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool)));
+
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
@@ -374,7 +541,7 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->peerWidget->verticalHeader()->hide();
ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
- ui->peerWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH);
@@ -382,14 +549,14 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
// create peer table context menu actions
- QAction* disconnectAction = new QAction(tr("&Disconnect Node"), this);
- QAction* banAction1h = new QAction(tr("Ban Node for") + " " + tr("1 &hour"), this);
- QAction* banAction24h = new QAction(tr("Ban Node for") + " " + tr("1 &day"), this);
- QAction* banAction7d = new QAction(tr("Ban Node for") + " " + tr("1 &week"), this);
- QAction* banAction365d = new QAction(tr("Ban Node for") + " " + tr("1 &year"), this);
+ QAction* disconnectAction = new QAction(tr("&Disconnect"), this);
+ QAction* banAction1h = new QAction(tr("Ban for") + " " + tr("1 &hour"), this);
+ QAction* banAction24h = new QAction(tr("Ban for") + " " + tr("1 &day"), this);
+ QAction* banAction7d = new QAction(tr("Ban for") + " " + tr("1 &week"), this);
+ QAction* banAction365d = new QAction(tr("Ban for") + " " + tr("1 &year"), this);
// create peer table context menu
- peersTableContextMenu = new QMenu();
+ peersTableContextMenu = new QMenu(this);
peersTableContextMenu->addAction(disconnectAction);
peersTableContextMenu->addAction(banAction1h);
peersTableContextMenu->addAction(banAction24h);
@@ -419,7 +586,9 @@ void RPCConsole::setClientModel(ClientModel *model)
this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &)));
// peer table signal handling - update peer details when new nodes are added to the model
connect(model->getPeerTableModel(), SIGNAL(layoutChanged()), this, SLOT(peerLayoutChanged()));
-
+ // peer table signal handling - cache selected node ids
+ connect(model->getPeerTableModel(), SIGNAL(layoutAboutToBeChanged()), this, SLOT(peerLayoutAboutToChange()));
+
// set up ban table
ui->banlistWidget->setModel(model->getBanTableModel());
ui->banlistWidget->verticalHeader()->hide();
@@ -432,10 +601,10 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
// create ban table context menu action
- QAction* unbanAction = new QAction(tr("&Unban Node"), this);
+ QAction* unbanAction = new QAction(tr("&Unban"), this);
// create ban table context menu
- banTableContextMenu = new QMenu();
+ banTableContextMenu = new QMenu(this);
banTableContextMenu->addAction(unbanAction);
// ban table context menu signals
@@ -461,11 +630,22 @@ 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.
+ startExecutor();
+ }
+ if (!model) {
+ // Client model is being set to 0, this means shutdown() is about to be called.
+ // Make sure we clean up the executor thread
+ Q_EMIT stopExecutor();
+ thread.wait();
}
}
@@ -545,13 +725,24 @@ void RPCConsole::clear(bool clearHistory)
"td.message { font-family: %1; font-size: %2; white-space:pre-wrap; } "
"td.cmd-request { color: #006060; } "
"td.cmd-error { color: red; } "
+ ".secwarning { color: red; }"
"b { color: #006060; } "
).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("Type <b>help</b> for an overview of available commands.")), true);
+ 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.") +
+ "</span>",
+ true);
}
void RPCConsole::keyPressEvent(QKeyEvent *event)
@@ -578,16 +769,30 @@ void RPCConsole::message(int category, const QString &message, bool html)
ui->messagesWidget->append(out);
}
+void RPCConsole::updateNetworkState()
+{
+ QString connections = QString::number(clientModel->getNumConnections()) + " (";
+ connections += tr("In:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_IN)) + " / ";
+ connections += tr("Out:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_OUT)) + ")";
+
+ if(!clientModel->getNetworkActive()) {
+ connections += " (" + tr("Network activity disabled") + ")";
+ }
+
+ ui->numberOfConnections->setText(connections);
+}
+
void RPCConsole::setNumConnections(int count)
{
if (!clientModel)
return;
- QString connections = QString::number(count) + " (";
- connections += tr("In:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_IN)) + " / ";
- connections += tr("Out:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_OUT)) + ")";
+ updateNetworkState();
+}
- ui->numberOfConnections->setText(connections);
+void RPCConsole::setNetworkActive(bool networkActive)
+{
+ updateNetworkState();
}
void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers)
@@ -611,12 +816,30 @@ void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage)
void RPCConsole::on_lineEdit_returnPressed()
{
QString cmd = ui->lineEdit->text();
- ui->lineEdit->clear();
if(!cmd.isEmpty())
{
- message(CMD_REQUEST, cmd);
+ std::string strFilteredCmd;
+ try {
+ std::string dummy;
+ if (!RPCParseCommandLine(dummy, cmd.toStdString(), false, &strFilteredCmd)) {
+ // Failed to parse command, so we cannot even filter it for the history
+ throw std::runtime_error("Invalid command line");
+ }
+ } catch (const std::exception& e) {
+ QMessageBox::critical(this, "Error", QString("Error: ") + QString::fromStdString(e.what()));
+ return;
+ }
+
+ ui->lineEdit->clear();
+
+ cmdBeforeBrowsing = QString();
+
+ message(CMD_REQUEST, QString::fromStdString(strFilteredCmd));
Q_EMIT cmdRequest(cmd);
+
+ cmd = QString::fromStdString(strFilteredCmd);
+
// Remove command, if already in history
history.removeOne(cmd);
// Append command to history
@@ -626,6 +849,7 @@ void RPCConsole::on_lineEdit_returnPressed()
history.removeFirst();
// Set pointer to end of history
historyPtr = history.size();
+
// Scroll console view to end
scrollToEnd();
}
@@ -633,6 +857,11 @@ void RPCConsole::on_lineEdit_returnPressed()
void RPCConsole::browseHistory(int offset)
{
+ // store current text when start browsing through the history
+ if (historyPtr == history.size()) {
+ cmdBeforeBrowsing = ui->lineEdit->text();
+ }
+
historyPtr += offset;
if(historyPtr < 0)
historyPtr = 0;
@@ -641,14 +870,16 @@ void RPCConsole::browseHistory(int offset)
QString cmd;
if(historyPtr < history.size())
cmd = history.at(historyPtr);
+ else if (!cmdBeforeBrowsing.isNull()) {
+ cmd = cmdBeforeBrowsing;
+ }
ui->lineEdit->setText(cmd);
}
void RPCConsole::startExecutor()
{
- QThread *thread = new QThread;
RPCExecutor *executor = new RPCExecutor();
- executor->moveToThread(thread);
+ executor->moveToThread(&thread);
// Replies from executor object must go to this object
connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString)));
@@ -656,16 +887,14 @@ void RPCConsole::startExecutor()
connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString)));
// On stopExecutor signal
- // - queue executor for deletion (in execution thread)
// - quit the Qt event loop in the execution thread
- connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater()));
- connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit()));
- // Queue the thread for deletion (in this thread) when it is finished
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ connect(this, SIGNAL(stopExecutor()), &thread, SLOT(quit()));
+ // - queue executor for deletion (in execution thread)
+ connect(&thread, SIGNAL(finished()), executor, SLOT(deleteLater()), Qt::DirectConnection);
// Default implementation of QThread::run() simply spins up an event loop in the thread,
// which is what we want.
- thread->start();
+ thread.start();
}
void RPCConsole::on_tabWidget_currentChanged(int index)
@@ -730,6 +959,17 @@ void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelecti
updateNodeDetail(stats);
}
+void RPCConsole::peerLayoutAboutToChange()
+{
+ QModelIndexList selected = ui->peerWidget->selectionModel()->selectedIndexes();
+ cachedNodeids.clear();
+ for(int i = 0; i < selected.size(); i++)
+ {
+ const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.at(i).row());
+ cachedNodeids.append(stats->nodeStats.nodeid);
+ }
+}
+
void RPCConsole::peerLayoutChanged()
{
if (!clientModel || !clientModel->getPeerTableModel())
@@ -739,7 +979,7 @@ void RPCConsole::peerLayoutChanged()
bool fUnselect = false;
bool fReselect = false;
- if (cachedNodeid == -1) // no node selected yet
+ if (cachedNodeids.empty()) // no node selected yet
return;
// find the currently selected row
@@ -751,7 +991,7 @@ void RPCConsole::peerLayoutChanged()
// check if our detail node has a row in the table (it may not necessarily
// be at selectedRow since its position can change after a layout change)
- int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeid);
+ int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeids.first());
if (detailNodeRow < 0)
{
@@ -777,7 +1017,10 @@ void RPCConsole::peerLayoutChanged()
if (fReselect)
{
- ui->peerWidget->selectRow(detailNodeRow);
+ for(int i = 0; i < cachedNodeids.size(); i++)
+ {
+ ui->peerWidget->selectRow(clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeids.at(i)));
+ }
}
if (stats)
@@ -786,9 +1029,6 @@ void RPCConsole::peerLayoutChanged()
void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
{
- // Update cached nodeid
- cachedNodeid = stats->nodeStats.nodeid;
-
// update the detail ui with latest node information
QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " ");
peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
@@ -796,13 +1036,14 @@ 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));
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
ui->peerVersion->setText(QString("%1").arg(QString::number(stats->nodeStats.nVersion)));
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
@@ -875,34 +1116,46 @@ void RPCConsole::showBanTableContextMenu(const QPoint& point)
void RPCConsole::disconnectSelectedNode()
{
- // Get currently selected peer address
- QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
- // Find the node, disconnect it and clear the selected node
- if (CNode *bannedNode = FindNode(strNode.toStdString())) {
- bannedNode->fDisconnect = true;
- clearSelectedNode();
+ if(!g_connman)
+ return;
+
+ // Get selected peer addresses
+ QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
+ for(int i = 0; i < nodes.count(); i++)
+ {
+ // Get currently selected peer address
+ NodeId id = nodes.at(i).data().toLongLong();
+ // Find the node, disconnect it and clear the selected node
+ if(g_connman->DisconnectNode(id))
+ clearSelectedNode();
}
}
void RPCConsole::banSelectedNode(int bantime)
{
- if (!clientModel)
+ if (!clientModel || !g_connman)
return;
-
- // Get currently selected peer address
- QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
- // Find possible nodes, ban it and clear the selected node
- if (FindNode(strNode.toStdString())) {
- std::string nStr = strNode.toStdString();
- std::string addr;
- int port = 0;
- SplitHostPort(nStr, port, addr);
-
- CNode::Ban(CNetAddr(addr), BanReasonManuallyAdded, bantime);
-
- clearSelectedNode();
- clientModel->getBanTableModel()->refresh();
+
+ // Get selected peer addresses
+ QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
+ for(int i = 0; i < nodes.count(); i++)
+ {
+ // Get currently selected peer address
+ NodeId id = nodes.at(i).data().toLongLong();
+
+ // Get currently selected peer address
+ int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(id);
+ if(detailNodeRow < 0)
+ return;
+
+ // Find possible nodes, ban it and clear the selected node
+ const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
+ if(stats) {
+ g_connman->Ban(stats->nodeStats.addr, BanReasonManuallyAdded, bantime);
+ }
}
+ clearSelectedNode();
+ clientModel->getBanTableModel()->refresh();
}
void RPCConsole::unbanSelectedNode()
@@ -910,21 +1163,27 @@ void RPCConsole::unbanSelectedNode()
if (!clientModel)
return;
- // Get currently selected ban address
- QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address);
- CSubNet possibleSubnet(strNode.toStdString());
-
- if (possibleSubnet.IsValid())
+ // Get selected ban addresses
+ QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->banlistWidget, BanTableModel::Address);
+ for(int i = 0; i < nodes.count(); i++)
{
- CNode::Unban(possibleSubnet);
- clientModel->getBanTableModel()->refresh();
+ // Get currently selected ban address
+ QString strNode = nodes.at(i).data().toString();
+ CSubNet possibleSubnet;
+
+ LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
+ if (possibleSubnet.IsValid() && g_connman)
+ {
+ g_connman->Unban(possibleSubnet);
+ clientModel->getBanTableModel()->refresh();
+ }
}
}
void RPCConsole::clearSelectedNode()
{
ui->peerWidget->selectionModel()->clearSelection();
- cachedNodeid = -1;
+ cachedNodeids.clear();
ui->detailWidget->hide();
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 28affa954d..ec531c99c8 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -12,6 +12,7 @@
#include <QWidget>
#include <QCompleter>
+#include <QThread>
class ClientModel;
class PlatformStyle;
@@ -35,6 +36,11 @@ 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) {
+ return RPCParseCommandLine(strResult, strCommand, true, pstrFilteredOut);
+ }
+
void setClientModel(ClientModel *model);
enum MessageClass {
@@ -86,6 +92,8 @@ public Q_SLOTS:
void message(int category, const QString &message, bool html = false);
/** Set number of connections shown in the UI */
void setNumConnections(int count);
+ /** Set network state shown in the UI */
+ void setNetworkActive(bool networkActive);
/** Set number of blocks and last block date shown in the UI */
void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers);
/** Set size (number of transactions and memory usage) of the mempool in the UI */
@@ -96,6 +104,8 @@ public Q_SLOTS:
void scrollToEnd();
/** Handle selection of peer in peers list */
void peerSelected(const QItemSelection &selected, const QItemSelection &deselected);
+ /** Handle selection caching before update */
+ void peerLayoutAboutToChange();
/** Handle updated peer information */
void peerLayoutChanged();
/** Disconnect a selected node on the Peers tab */
@@ -133,13 +143,18 @@ private:
ClientModel *clientModel;
QStringList history;
int historyPtr;
- NodeId cachedNodeid;
+ QString cmdBeforeBrowsing;
+ QList<NodeId> cachedNodeids;
const PlatformStyle *platformStyle;
RPCTimerInterface *rpcTimerInterface;
QMenu *peersTableContextMenu;
QMenu *banTableContextMenu;
int consoleFontSize;
QCompleter *autoCompleter;
+ QThread thread;
+
+ /** Update UI with latest network info from model. */
+ void updateNetworkState();
};
#endif // BITCOIN_QT_RPCCONSOLE_H
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 6d50be56ec..098cda6d32 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -16,12 +16,15 @@
#include "walletmodel.h"
#include "base58.h"
-#include "coincontrol.h"
-#include "main.h" // mempool and minRelayTxFee
+#include "chainparams.h"
+#include "wallet/coincontrol.h"
+#include "validation.h" // mempool and minRelayTxFee
#include "ui_interface.h"
#include "txmempool.h"
+#include "policy/fees.h"
#include "wallet/wallet.h"
+#include <QFontMetrics>
#include <QMessageBox>
#include <QScrollBar>
#include <QSettings>
@@ -30,25 +33,25 @@
#define SEND_CONFIRM_DELAY 3
-SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
+SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SendCoinsDialog),
clientModel(0),
model(0),
fNewRecipientAllowed(true),
fFeeMinimized(true),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
ui->setupUi(this);
- if (!platformStyle->getImagesOnButtons()) {
+ if (!_platformStyle->getImagesOnButtons()) {
ui->addButton->setIcon(QIcon());
ui->clearButton->setIcon(QIcon());
ui->sendButton->setIcon(QIcon());
} else {
- ui->addButton->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
- ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
- ui->sendButton->setIcon(platformStyle->SingleColorIcon(":/icons/send"));
+ ui->addButton->setIcon(_platformStyle->SingleColorIcon(":/icons/add"));
+ ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->sendButton->setIcon(_platformStyle->SingleColorIcon(":/icons/send"));
}
GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this);
@@ -69,7 +72,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
- QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity()));
@@ -77,7 +79,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardFee()));
connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAfterFee()));
connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardBytes()));
- connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardPriority()));
connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardLowOutput()));
connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardChange()));
ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
@@ -85,7 +86,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
ui->labelCoinControlFee->addAction(clipboardFeeAction);
ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
ui->labelCoinControlBytes->addAction(clipboardBytesAction);
- ui->labelCoinControlPriority->addAction(clipboardPriorityAction);
ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
ui->labelCoinControlChange->addAction(clipboardChangeAction);
@@ -113,46 +113,45 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
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->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt());
ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());
ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool());
minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
}
-void SendCoinsDialog::setClientModel(ClientModel *clientModel)
+void SendCoinsDialog::setClientModel(ClientModel *_clientModel)
{
- this->clientModel = clientModel;
+ this->clientModel = _clientModel;
- if (clientModel) {
- connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel()));
+ if (_clientModel) {
+ connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel()));
}
}
-void SendCoinsDialog::setModel(WalletModel *model)
+void SendCoinsDialog::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
- if(model && model->getOptionsModel())
+ if(_model && _model->getOptionsModel())
{
for(int i = 0; i < ui->entries->count(); ++i)
{
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
if(entry)
{
- entry->setModel(model);
+ entry->setModel(_model);
}
}
- setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(),
- model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance());
- connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
- connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
+ setBalance(_model->getBalance(), _model->getUnconfirmedBalance(), _model->getImmatureBalance(),
+ _model->getWatchBalance(), _model->getWatchUnconfirmedBalance(), _model->getWatchImmatureBalance());
+ connect(_model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
+ connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
updateDisplayUnit();
// Coin Control
- connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels()));
- connect(model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool)));
- ui->frameCoinControl->setVisible(model->getOptionsModel()->getCoinControlFeatures());
+ connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels()));
+ connect(_model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool)));
+ ui->frameCoinControl->setVisible(_model->getOptionsModel()->getCoinControlFeatures());
coinControlUpdateLabels();
// fee section
@@ -175,6 +174,16 @@ void SendCoinsDialog::setModel(WalletModel *model)
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);
+ else
+ ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt());
}
}
@@ -232,10 +241,19 @@ void SendCoinsDialog::on_sendButton_clicked()
// prepare transaction for getting txFee earlier
WalletModelTransaction currentTransaction(recipients);
WalletModel::SendCoinsReturn prepareStatus;
- if (model->getOptionsModel()->getCoinControlFeatures()) // coin control enabled
- prepareStatus = model->prepareTransaction(currentTransaction, CoinControlDialog::coinControl);
+
+ // Always use a CCoinControl instance, use the CoinControlDialog instance if CoinControl has been enabled
+ CCoinControl ctrl;
+ if (model->getOptionsModel()->getCoinControlFeatures())
+ ctrl = *CoinControlDialog::coinControl;
+ if (ui->radioSmartFee->isChecked())
+ ctrl.nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
else
- prepareStatus = model->prepareTransaction(currentTransaction);
+ ctrl.nConfirmTarget = 0;
+
+ ctrl.signalRbf = ui->optInRBF->isChecked();
+
+ prepareStatus = model->prepareTransaction(currentTransaction, &ctrl);
// process prepareStatus and on error generate message shown to user
processSendCoinsReturn(prepareStatus,
@@ -314,6 +332,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();
@@ -524,7 +549,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
msgParams.second = CClientUIInterface::MSG_ERROR;
break;
case WalletModel::TransactionCommitFailed:
- msgParams.first = tr("The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
+ msgParams.first = tr("The transaction was rejected with the following reason: %1").arg(sendCoinsReturn.reasonCommitFailed);
msgParams.second = CClientUIInterface::MSG_ERROR;
break;
case WalletModel::AbsurdFee:
@@ -579,6 +604,7 @@ void SendCoinsDialog::updateFeeSectionControls()
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());
@@ -590,12 +616,17 @@ void SendCoinsDialog::updateGlobalFeeVariables()
{
if (ui->radioSmartFee->isChecked())
{
- nTxConfirmTarget = defaultConfirmTarget - ui->sliderSmartFee->value();
+ 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 required time for confirmation
+ ui->confirmationTargetLabel->setText(GUIUtil::formatDurationStr(nConfirmTarget * Params().GetConsensus().nPowTargetSpacing) + " / " + tr("%n block(s)", "", nConfirmTarget));
}
else
{
- nTxConfirmTarget = defaultConfirmTarget;
payTxFee = CFeeRate(ui->customFee->value());
// if user has selected to set a minimum absolute fee, pass the value to coincontrol
@@ -630,15 +661,20 @@ void SendCoinsDialog::updateSmartFeeLabel()
if(!model || !model->getOptionsModel())
return;
- int nBlocksToConfirm = defaultConfirmTarget - ui->sliderSmartFee->value();
+ int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
int estimateFoundAtBlocks = nBlocksToConfirm;
- CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks);
+ CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks, ::mempool);
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->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
{
@@ -646,6 +682,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
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->fallbackFeeWarningLabel->setVisible(false);
}
updateFeeMinimizedLabel();
@@ -681,12 +718,6 @@ void SendCoinsDialog::coinControlClipboardBytes()
GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));
}
-// Coin Control: copy label "Priority" to clipboard
-void SendCoinsDialog::coinControlClipboardPriority()
-{
- GUIUtil::setClipboard(ui->labelCoinControlPriority->text());
-}
-
// Coin Control: copy label "Dust" to clipboard
void SendCoinsDialog::coinControlClipboardLowOutput()
{
@@ -707,6 +738,8 @@ 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();
}
@@ -760,6 +793,19 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
if (!model->havePrivKey(keyid)) // Unknown change address
{
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
+
+ // confirmation dialog
+ QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm custom change address"), tr("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?"),
+ QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
+
+ if(btnRetVal == QMessageBox::Yes)
+ CoinControlDialog::coinControl->destChange = addr.Get();
+ else
+ {
+ ui->lineEditCoinControlChange->setText("");
+ ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}");
+ ui->labelCoinControlChangeLabel->setText("");
+ }
}
else // Known change address
{
@@ -790,7 +836,7 @@ void SendCoinsDialog::coinControlUpdateLabels()
ui->radioCustomAtLeast->setVisible(true);
// only enable the feature if inputs are selected
- ui->radioCustomAtLeast->setEnabled(CoinControlDialog::coinControl->HasSelected());
+ ui->radioCustomAtLeast->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked() &&CoinControlDialog::coinControl->HasSelected());
}
else
{
@@ -832,9 +878,9 @@ void SendCoinsDialog::coinControlUpdateLabels()
}
}
-SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int secDelay,
+SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int _secDelay,
QWidget *parent) :
- QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(secDelay)
+ QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(_secDelay)
{
setDefaultButton(QMessageBox::Cancel);
yesButton = button(QMessageBox::Yes);
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index be4f2ee44b..a402edc961 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -26,8 +26,6 @@ QT_BEGIN_NAMESPACE
class QUrl;
QT_END_NAMESPACE
-const int defaultConfirmTarget = 25;
-
/** Dialog for sending bitcoins */
class SendCoinsDialog : public QDialog
{
@@ -88,7 +86,6 @@ private Q_SLOTS:
void coinControlClipboardFee();
void coinControlClipboardAfterFee();
void coinControlClipboardBytes();
- void coinControlClipboardPriority();
void coinControlClipboardLowOutput();
void coinControlClipboardChange();
void setMinimumFee();
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index d063f2c891..bb0f47b21c 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -15,11 +15,11 @@
#include <QApplication>
#include <QClipboard>
-SendCoinsEntry::SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent) :
+SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *parent) :
QStackedWidget(parent),
ui(new Ui::SendCoinsEntry),
model(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
ui->setupUi(this);
@@ -79,12 +79,12 @@ void SendCoinsEntry::on_payTo_textChanged(const QString &address)
updateLabel(address);
}
-void SendCoinsEntry::setModel(WalletModel *model)
+void SendCoinsEntry::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
- if (model && model->getOptionsModel())
- connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
+ if (_model && _model->getOptionsModel())
+ connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
clear();
}
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 8e2e8a5098..0950ed0234 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -12,7 +12,7 @@
#include "base58.h"
#include "init.h"
-#include "main.h" // For strMessageMagic
+#include "validation.h" // For strMessageMagic
#include "wallet/wallet.h"
#include <string>
@@ -20,11 +20,11 @@
#include <QClipboard>
-SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *platformStyle, QWidget *parent) :
+SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SignVerifyMessageDialog),
model(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
ui->setupUi(this);
@@ -60,9 +60,9 @@ SignVerifyMessageDialog::~SignVerifyMessageDialog()
delete ui;
}
-void SignVerifyMessageDialog::setModel(WalletModel *model)
+void SignVerifyMessageDialog::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
}
void SignVerifyMessageDialog::setAddress_SM(const QString &address)
@@ -142,7 +142,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
}
CKey key;
- if (!pwalletMain->GetKey(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."));
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index e36d86fddd..f4377247e1 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -147,6 +147,7 @@ void SplashScreen::slotFinish(QWidget *mainWin)
if (isMinimized())
showNormal();
hide();
+ deleteLater(); // No more need for this
}
static void InitMessage(SplashScreen *splash, const std::string &message)
@@ -164,9 +165,10 @@ static void ShowProgress(SplashScreen *splash, const std::string &title, int nPr
}
#ifdef ENABLE_WALLET
-static void ConnectWallet(SplashScreen *splash, CWallet* wallet)
+void SplashScreen::ConnectWallet(CWallet* wallet)
{
- wallet->ShowProgress.connect(boost::bind(ShowProgress, splash, _1, _2));
+ wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
+ connectedWallets.push_back(wallet);
}
#endif
@@ -176,7 +178,7 @@ void SplashScreen::subscribeToCoreSignals()
uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1));
uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
#ifdef ENABLE_WALLET
- uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, _1));
+ uiInterface.LoadWallet.connect(boost::bind(&SplashScreen::ConnectWallet, this, _1));
#endif
}
@@ -186,8 +188,9 @@ void SplashScreen::unsubscribeFromCoreSignals()
uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1));
uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
#ifdef ENABLE_WALLET
- if(pwalletMain)
- pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
+ Q_FOREACH(CWallet* const & pwallet, connectedWallets) {
+ pwallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
+ }
#endif
}
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index 821f39db1c..95a65cc53c 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -7,6 +7,7 @@
#include <QSplashScreen>
+class CWallet;
class NetworkStyle;
/** Class for the splashscreen with information of the running client.
@@ -39,11 +40,15 @@ private:
void subscribeToCoreSignals();
/** Disconnect core signals to splash screen */
void unsubscribeFromCoreSignals();
+ /** Connect wallet signals to splash screen */
+ void ConnectWallet(CWallet*);
QPixmap pixmap;
QString curMessage;
QColor curColor;
int curAlignment;
+
+ QList<CWallet*> connectedWallets;
};
#endif // BITCOIN_QT_SPLASHSCREEN_H
diff --git a/src/qt/test/compattests.cpp b/src/qt/test/compattests.cpp
new file mode 100644
index 0000000000..2a7284b5b2
--- /dev/null
+++ b/src/qt/test/compattests.cpp
@@ -0,0 +1,23 @@
+// Copyright (c) 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 "paymentrequestplus.h" // this includes protobuf's port.h which defines its own bswap macos
+
+#include "compattests.h"
+
+#include "compat/byteswap.h"
+
+void CompatTests::bswapTests()
+{
+ // Sibling in bitcoin/src/test/bswap_tests.cpp
+ uint16_t u1 = 0x1234;
+ uint32_t u2 = 0x56789abc;
+ uint64_t u3 = 0xdef0123456789abc;
+ uint16_t e1 = 0x3412;
+ uint32_t e2 = 0xbc9a7856;
+ uint64_t e3 = 0xbc9a78563412f0de;
+ QVERIFY(bswap_16(u1) == e1);
+ QVERIFY(bswap_32(u2) == e2);
+ QVERIFY(bswap_64(u3) == e3);
+}
diff --git a/src/qt/test/compattests.h b/src/qt/test/compattests.h
new file mode 100644
index 0000000000..1af97696b2
--- /dev/null
+++ b/src/qt/test/compattests.h
@@ -0,0 +1,19 @@
+// 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_QT_TEST_COMPATTESTS_H
+#define BITCOIN_QT_TEST_COMPATTESTS_H
+
+#include <QObject>
+#include <QTest>
+
+class CompatTests : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void bswapTests();
+};
+
+#endif // BITCOIN_QT_TEST_COMPATTESTS_H
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index 84ccfea730..08a76c7d49 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -142,7 +142,7 @@ void PaymentServerTests::paymentServerTests()
byteArray = QByteArray((const char*)&data[0], 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);
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
new file mode 100644
index 0000000000..dada689731
--- /dev/null
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -0,0 +1,159 @@
+// Copyright (c) 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 "rpcnestedtests.h"
+
+#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 "univalue.h"
+#include "util.h"
+
+#include <QDir>
+#include <QtGlobal>
+
+static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
+{
+ if (request.fHelp) {
+ return "help message";
+ }
+ return request.params.write(0, 0);
+}
+
+static const CRPCCommand vRPCCommands[] =
+{
+ { "test", "rpcNestedTest", &rpcNestedTest_rpc, true, {} },
+};
+
+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);
+ }
+
+ SetRPCWarmupFinished();
+
+ std::string result;
+ std::string result2;
+ std::string filtered;
+ RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path
+ QVERIFY(result=="main");
+ QVERIFY(filtered == "getblockchaininfo()[chain]");
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())"); //simple 2 level nesting
+ RPCConsole::RPCExecuteCommandLine(result, "getblock(getblock(getbestblockhash())[hash], true)");
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo");
+ QVERIFY(result.substr(0,1) == "{");
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()");
+ QVERIFY(result.substr(0,1) == "{");
+
+ 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
+ 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
+ QVERIFY(result == result2);
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]", &filtered);
+ QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
+ QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]");
+
+ RPCConsole::RPCParseCommandLine(result, "importprivkey", false, &filtered);
+ QVERIFY(filtered == "importprivkey(…)");
+ RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc", false, &filtered);
+ QVERIFY(filtered == "signmessagewithprivkey(…)");
+ RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc,def", false, &filtered);
+ QVERIFY(filtered == "signmessagewithprivkey(…)");
+ RPCConsole::RPCParseCommandLine(result, "signrawtransaction(abc)", false, &filtered);
+ QVERIFY(filtered == "signrawtransaction(…)");
+ RPCConsole::RPCParseCommandLine(result, "walletpassphrase(help())", false, &filtered);
+ QVERIFY(filtered == "walletpassphrase(…)");
+ RPCConsole::RPCParseCommandLine(result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered);
+ QVERIFY(filtered == "walletpassphrasechange(…)");
+ RPCConsole::RPCParseCommandLine(result, "help(encryptwallet(abc, def))", false, &filtered);
+ QVERIFY(filtered == "help(encryptwallet(…))");
+ RPCConsole::RPCParseCommandLine(result, "help(importprivkey())", false, &filtered);
+ QVERIFY(filtered == "help(importprivkey(…))");
+ RPCConsole::RPCParseCommandLine(result, "help(importprivkey(help()))", false, &filtered);
+ QVERIFY(filtered == "help(importprivkey(…))");
+ RPCConsole::RPCParseCommandLine(result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered);
+ QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))");
+
+ RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest");
+ QVERIFY(result == "[]");
+ RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest ''");
+ QVERIFY(result == "[\"\"]");
+ RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest \"\"");
+ QVERIFY(result == "[\"\"]");
+ RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest '' abc");
+ QVERIFY(result == "[\"\",\"abc\"]");
+ RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc '' abc");
+ QVERIFY(result == "[\"abc\",\"\",\"abc\"]");
+ RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc abc");
+ QVERIFY(result == "[\"abc\",\"abc\"]");
+ RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc\t\tabc");
+ QVERIFY(result == "[\"abc\",\"abc\"]");
+ RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc )");
+ QVERIFY(result == "[\"abc\"]");
+ RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest( abc )");
+ QVERIFY(result == "[\"abc\"]");
+ RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest( abc , cba )");
+ QVERIFY(result == "[\"abc\",\"cba\"]");
+
+#if QT_VERSION >= 0x050300
+ // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
+ (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
+ (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found
+ 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,,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
+
+ UnloadBlockIndex();
+ delete pcoinsTip;
+ pcoinsTip = nullptr;
+ delete pcoinsdbview;
+ pcoinsdbview = nullptr;
+ delete pblocktree;
+ pblocktree = nullptr;
+
+ fs::remove_all(fs::path(path));
+}
diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h
new file mode 100644
index 0000000000..9ad409019f
--- /dev/null
+++ b/src/qt/test/rpcnestedtests.h
@@ -0,0 +1,25 @@
+// Copyright (c) 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_QT_TEST_RPC_NESTED_TESTS_H
+#define BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
+
+#include <QObject>
+#include <QTest>
+
+#include "txdb.h"
+#include "txmempool.h"
+
+class RPCNestedTests : public QObject
+{
+ Q_OBJECT
+
+ private Q_SLOTS:
+ void rpcNestedTests();
+
+private:
+ CCoinsViewDB *pcoinsdbview;
+};
+
+#endif // BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index db193420bf..cae18f41a5 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -6,47 +6,91 @@
#include "config/bitcoin-config.h"
#endif
+#include "chainparams.h"
+#include "rpcnestedtests.h"
#include "util.h"
#include "uritests.h"
+#include "compattests.h"
#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();
+
// This is all you need to run all the tests
int main(int argc, char *argv[])
{
SetupEnvironment();
+ SetupNetworking();
+ SelectParams(CBaseChainParams::MAIN);
+ noui_connect();
+
bool fInvalid = false;
+ // Prefer the "minimal" platform for the test instead of the normal default
+ // platform ("xcb", "windows", or "cocoa") so tests can't unintentially
+ // interfere with any background GUIs and don't require extra resources.
+ setenv("QT_QPA_PLATFORM", "minimal", 0);
+
// 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) {
+ fInvalid = true;
+ }
+ CompatTests test4;
+ if (QTest::qExec(&test4) != 0) {
+ fInvalid = true;
+ }
+#ifdef ENABLE_WALLET
+ WalletTests test5;
+ if (QTest::qExec(&test5) != 0) {
fInvalid = true;
+ }
#endif
return fInvalid;
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
new file mode 100644
index 0000000000..a0dce3d997
--- /dev/null
+++ b/src/qt/test/wallettests.cpp
@@ -0,0 +1,119 @@
+#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/walletmodel.h"
+#include "test/test_bitcoin.h"
+#include "validation.h"
+#include "wallet/wallet.h"
+
+#include <QAbstractButton>
+#include <QApplication>
+#include <QTimer>
+#include <QVBoxLayout>
+
+namespace
+{
+//! Press "Yes" button in modal send confirmation dialog.
+void ConfirmSend()
+{
+ QTimer::singleShot(0, makeCallback([](Callback* callback) {
+ for (QWidget* widget : QApplication::topLevelWidgets()) {
+ if (widget->inherits("SendConfirmationDialog")) {
+ SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
+ QAbstractButton* button = dialog->button(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 CBitcoinAddress& address, CAmount amount)
+{
+ QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
+ SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
+ entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(address.ToString()));
+ entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
+ 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 {};
+}
+}
+
+//! 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 WalletTests::walletTests()
+{
+ // Set up wallet and chain with 101 blocks (1 mature block for spending).
+ TestChain100Setup test;
+ 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());
+ OptionsModel optionsModel;
+ WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel);
+ sendCoinsDialog.setModel(&walletModel);
+
+ // Send two transactions, and verify they are added to transaction list.
+ TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
+ QCOMPARE(transactionTableModel->rowCount({}), 101);
+ uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN);
+ uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN);
+ QCOMPARE(transactionTableModel->rowCount({}), 103);
+ QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
+ QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
+
+ bitdb.Flush(true);
+ bitdb.Reset();
+}
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/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index bae0cbd1c8..d81188895b 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -11,7 +11,7 @@
#include "base58.h"
#include "consensus/consensus.h"
-#include "main.h"
+#include "validation.h"
#include "script/script.h"
#include "timedata.h"
#include "util.h"
@@ -26,10 +26,10 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
AssertLockHeld(cs_main);
if (!CheckFinalTx(wtx))
{
- if (wtx.nLockTime < LOCKTIME_THRESHOLD)
- return tr("Open for %n more block(s)", "", wtx.nLockTime - chainActive.Height());
+ if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
+ return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - chainActive.Height());
else
- return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
+ return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime));
}
else
{
@@ -133,7 +133,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
// Coinbase
//
CAmount nUnmatured = 0;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
nUnmatured += wallet->GetCredit(txout, ISMINE_ALL);
strHTML += "<b>" + tr("Credit") + ":</b> ";
if (wtx.IsInMainChain())
@@ -152,14 +152,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
else
{
isminetype fAllFromMe = ISMINE_SPENDABLE;
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ BOOST_FOREACH(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.vout)
+ BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
{
isminetype mine = wallet->IsMine(txout);
if(fAllToMe > mine) fAllToMe = mine;
@@ -173,7 +173,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
//
// Debit
//
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
{
// Ignore change
isminetype toSelf = wallet->IsMine(txout);
@@ -212,7 +212,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>";
}
- CAmount nTxFee = nDebit - wtx.GetValueOut();
+ CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
if (nTxFee > 0)
strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "<br>";
}
@@ -221,10 +221,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
//
// Mixed debit transaction
//
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ BOOST_FOREACH(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.vout)
+ BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
if (wallet->IsMine(txout))
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
}
@@ -241,6 +241,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxID() + "<br>";
+ strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.tx->GetTotalSize()) + " bytes<br>";
strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
@@ -272,23 +273,23 @@ 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.vin)
+ BOOST_FOREACH(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.vout)
+ BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
if(wallet->IsMine(txout))
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
- strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
+ strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true);
strHTML += "<br><b>" + tr("Inputs") + ":</b>";
strHTML += "<ul>";
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
COutPoint prevout = txin.prevout;
diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp
index 65adcc4f02..65f163deb2 100644
--- a/src/qt/transactiondescdialog.cpp
+++ b/src/qt/transactiondescdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2014 The Bitcoin Core developers
+// 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.
diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp
index 9dcb72f55e..44e4ef8238 100644
--- a/src/qt/transactionfilterproxy.cpp
+++ b/src/qt/transactionfilterproxy.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2014 The Bitcoin Core developers
+// 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.
@@ -66,9 +66,9 @@ void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime
invalidateFilter();
}
-void TransactionFilterProxy::setAddressPrefix(const QString &addrPrefix)
+void TransactionFilterProxy::setAddressPrefix(const QString &_addrPrefix)
{
- this->addrPrefix = addrPrefix;
+ this->addrPrefix = _addrPrefix;
invalidateFilter();
}
@@ -95,9 +95,9 @@ void TransactionFilterProxy::setLimit(int limit)
this->limitRows = limit;
}
-void TransactionFilterProxy::setShowInactive(bool showInactive)
+void TransactionFilterProxy::setShowInactive(bool _showInactive)
{
- this->showInactive = showInactive;
+ this->showInactive = _showInactive;
invalidateFilter();
}
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 4fe47181f6..4bb260aa58 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -6,7 +6,7 @@
#include "base58.h"
#include "consensus/consensus.h"
-#include "main.h"
+#include "validation.h"
#include "timedata.h"
#include "wallet/wallet.h"
@@ -18,14 +18,8 @@
*/
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,14 +41,15 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
//
// Credit
//
- BOOST_FOREACH(const CTxOut& txout, wtx.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))
@@ -83,7 +78,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
bool involvesWatchAddress = false;
isminetype fAllFromMe = ISMINE_SPENDABLE;
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
isminetype mine = wallet->IsMine(txin);
if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
@@ -91,7 +86,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
}
isminetype fAllToMe = ISMINE_SPENDABLE;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
{
isminetype mine = wallet->IsMine(txout);
if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
@@ -112,13 +107,13 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
//
// Debit
//
- CAmount nTxFee = nDebit - wtx.GetValueOut();
+ CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
- for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
+ for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++)
{
- const CTxOut& txout = wtx.vout[nOut];
+ 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))
@@ -190,15 +185,15 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
if (!CheckFinalTx(wtx))
{
- if (wtx.nLockTime < LOCKTIME_THRESHOLD)
+ if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
{
status.status = TransactionStatus::OpenUntilBlock;
- status.open_for = wtx.nLockTime - chainActive.Height();
+ status.open_for = wtx.tx->nLockTime - chainActive.Height();
}
else
{
status.status = TransactionStatus::OpenUntilDate;
- status.open_for = wtx.nLockTime;
+ status.open_for = wtx.tx->nLockTime;
}
}
// For generated transactions, determine maturity
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index 8c754c3aad..5aabbbffa8 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2014 The Bitcoin Core developers
+// 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.
@@ -88,16 +88,16 @@ public:
{
}
- TransactionRecord(uint256 hash, qint64 time):
- hash(hash), time(time), type(Other), address(""), debit(0),
+ TransactionRecord(uint256 _hash, qint64 _time):
+ hash(_hash), time(_time), type(Other), address(""), debit(0),
credit(0), idx(0)
{
}
- TransactionRecord(uint256 hash, qint64 time,
- Type type, const std::string &address,
- const CAmount& debit, const CAmount& credit):
- hash(hash), time(time), type(type), address(address), debit(debit), credit(credit),
+ TransactionRecord(uint256 _hash, qint64 _time,
+ Type _type, const std::string &_address,
+ const CAmount& _debit, const CAmount& _credit):
+ hash(_hash), time(_time), type(_type), address(_address), debit(_debit), credit(_credit),
idx(0)
{
}
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index b29ecf8348..61466c8ed1 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -14,7 +14,7 @@
#include "walletmodel.h"
#include "core_io.h"
-#include "main.h"
+#include "validation.h"
#include "sync.h"
#include "uint256.h"
#include "util.h"
@@ -59,9 +59,9 @@ struct TxLessThan
class TransactionTablePriv
{
public:
- TransactionTablePriv(CWallet *wallet, TransactionTableModel *parent) :
- wallet(wallet),
- parent(parent)
+ TransactionTablePriv(CWallet *_wallet, TransactionTableModel *_parent) :
+ wallet(_wallet),
+ parent(_parent)
{
}
@@ -235,13 +235,13 @@ public:
}
};
-TransactionTableModel::TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent):
+TransactionTableModel::TransactionTableModel(const PlatformStyle *_platformStyle, CWallet* _wallet, WalletModel *parent):
QAbstractTableModel(parent),
- wallet(wallet),
+ wallet(_wallet),
walletModel(parent),
- priv(new TransactionTablePriv(wallet, this)),
+ priv(new TransactionTablePriv(_wallet, this)),
fProcessingQueuedTransactions(false),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
priv->refreshWallet();
@@ -714,8 +714,8 @@ struct TransactionNotification
{
public:
TransactionNotification() {}
- TransactionNotification(uint256 hash, ChangeType status, bool showTransaction):
- hash(hash), status(status), showTransaction(showTransaction) {}
+ TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction):
+ hash(_hash), status(_status), showTransaction(_showTransaction) {}
void invoke(QObject *ttm)
{
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index 6932646e1e..80aeb64c41 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 48cf940502..30f4db9450 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -37,7 +37,7 @@
TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent), model(0), transactionProxyModel(0),
- transactionView(0), abandonAction(0)
+ transactionView(0), abandonAction(0), columnResizingFixer(0)
{
// Build filter row
setContentsMargins(0,0,0,0);
@@ -147,7 +147,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
QAction *editLabelAction = new QAction(tr("Edit label"), this);
QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
- contextMenu = new QMenu();
+ contextMenu = new QMenu(this);
contextMenu->addAction(copyAddressAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(copyAmountAction);
@@ -184,13 +184,13 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails()));
}
-void TransactionView::setModel(WalletModel *model)
+void TransactionView::setModel(WalletModel *_model)
{
- this->model = model;
- if(model)
+ this->model = _model;
+ if(_model)
{
transactionProxyModel = new TransactionFilterProxy(this);
- transactionProxyModel->setSourceModel(model->getTransactionTableModel());
+ transactionProxyModel->setSourceModel(_model->getTransactionTableModel());
transactionProxyModel->setDynamicSortFilter(true);
transactionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
@@ -212,12 +212,12 @@ void TransactionView::setModel(WalletModel *model)
transactionView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH);
transactionView->setColumnWidth(TransactionTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH);
- columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH);
+ columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH, this);
- if (model->getOptionsModel())
+ if (_model->getOptionsModel())
{
// Add third party transaction URLs to context menu
- QStringList listUrls = model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts);
+ QStringList listUrls = _model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts);
for (int i = 0; i < listUrls.size(); ++i)
{
QString host = QUrl(listUrls[i].trimmed(), QUrl::StrictMode).host();
@@ -234,10 +234,10 @@ void TransactionView::setModel(WalletModel *model)
}
// show/hide column Watch-only
- updateWatchOnlyColumn(model->haveWatchOnly());
+ updateWatchOnlyColumn(_model->haveWatchOnly());
// Watch-only signal
- connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool)));
+ connect(_model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool)));
}
}
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index e9b9d5b6bc..595701cdd9 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 947bcdb15a..7ab4125284 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -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);
@@ -171,22 +171,20 @@ ShutdownWindow::ShutdownWindow(QWidget *parent, Qt::WindowFlags f):
setLayout(layout);
}
-void ShutdownWindow::showShutdownWindow(BitcoinGUI *window)
+QWidget *ShutdownWindow::showShutdownWindow(BitcoinGUI *window)
{
if (!window)
- return;
+ return nullptr;
// Show a simple window indicating shutdown status
QWidget *shutdownWindow = new ShutdownWindow();
- // We don't hold a direct pointer to the shutdown window after creation, so use
- // Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually.
- shutdownWindow->setAttribute(Qt::WA_DeleteOnClose);
shutdownWindow->setWindowTitle(window->windowTitle());
// Center shutdown window at where main window was
const QPoint global = window->mapToGlobal(window->rect().center());
shutdownWindow->move(global.x() - shutdownWindow->width() / 2, global.y() - shutdownWindow->height() / 2);
shutdownWindow->show();
+ return shutdownWindow;
}
void ShutdownWindow::closeEvent(QCloseEvent *event)
diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h
index 843bd7f67b..1b6781c5fc 100644
--- a/src/qt/utilitydialog.h
+++ b/src/qt/utilitydialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -43,7 +43,7 @@ class ShutdownWindow : public QWidget
public:
ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0);
- static void showShutdownWindow(BitcoinGUI *window);
+ static QWidget *showShutdownWindow(BitcoinGUI *window);
protected:
void closeEvent(QCloseEvent *event);
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index e4ca5e1831..f3183320f0 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -12,10 +12,10 @@
#include <QHBoxLayout>
#include <QLabel>
-WalletFrame::WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui) :
+WalletFrame::WalletFrame(const PlatformStyle *_platformStyle, BitcoinGUI *_gui) :
QFrame(_gui),
gui(_gui),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
// Leave HBox hook for adding a list view later
QHBoxLayout *walletFrameLayout = new QHBoxLayout(this);
@@ -33,9 +33,9 @@ WalletFrame::~WalletFrame()
{
}
-void WalletFrame::setClientModel(ClientModel *clientModel)
+void WalletFrame::setClientModel(ClientModel *_clientModel)
{
- this->clientModel = clientModel;
+ this->clientModel = _clientModel;
}
bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel)
@@ -57,6 +57,8 @@ bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel)
// Ensure a walletView is able to show the main window
connect(walletView, SIGNAL(showNormalIfMinimized()), gui, SLOT(showNormalIfMinimized()));
+ connect(walletView, SIGNAL(outOfSyncWarningClicked()), this, SLOT(outOfSyncWarningClicked()));
+
return true;
}
@@ -195,3 +197,7 @@ WalletView *WalletFrame::currentWalletView()
return qobject_cast<WalletView*>(walletStack->currentWidget());
}
+void WalletFrame::outOfSyncWarningClicked()
+{
+ Q_EMIT requestedSyncWarningInfo();
+}
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
index 9a5bc273c2..42ce69fea1 100644
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -19,6 +19,13 @@ QT_BEGIN_NAMESPACE
class QStackedWidget;
QT_END_NAMESPACE
+/**
+ * A container for embedding all wallet-related
+ * controls into BitcoinGUI. The purpose of this class is to allow future
+ * refinements of the wallet controls with minimal need for further
+ * modifications to BitcoinGUI, thus greatly simplifying merges while
+ * reducing the risk of breaking top-level stuff.
+ */
class WalletFrame : public QFrame
{
Q_OBJECT
@@ -38,6 +45,10 @@ public:
void showOutOfSyncWarning(bool fShow);
+Q_SIGNALS:
+ /** Notify that the user has requested more information about the out-of-sync warning */
+ void requestedSyncWarningInfo();
+
private:
QStackedWidget *walletStack;
BitcoinGUI *gui;
@@ -78,6 +89,8 @@ public Q_SLOTS:
void usedSendingAddresses();
/** Show used receiving addresses */
void usedReceivingAddresses();
+ /** Pass on signal over requested out-of-sync-warning information */
+ void outOfSyncWarningClicked();
};
#endif // BITCOIN_QT_WALLETFRAME_H
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 3867310cd6..a2a9271904 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -1,10 +1,11 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
#include "walletmodel.h"
#include "addresstablemodel.h"
+#include "consensus/validation.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "paymentserver.h"
@@ -12,10 +13,13 @@
#include "transactiontablemodel.h"
#include "base58.h"
+#include "chain.h"
#include "keystore.h"
-#include "main.h"
+#include "validation.h"
+#include "net.h" // for g_connman
#include "sync.h"
#include "ui_interface.h"
+#include "util.h" // for GetBoolArg
#include "wallet/wallet.h"
#include "wallet/walletdb.h" // for BackupWallet
@@ -27,8 +31,8 @@
#include <boost/foreach.hpp>
-WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
- QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
+WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *_wallet, OptionsModel *_optionsModel, QObject *parent) :
+ QObject(parent), wallet(_wallet), optionsModel(_optionsModel), addressTableModel(0),
transactionTableModel(0),
recentRequestsTableModel(0),
cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
@@ -64,7 +68,7 @@ CAmount WalletModel::getBalance(const CCoinControl *coinControl) const
wallet->AvailableCoins(vCoins, true, coinControl);
BOOST_FOREACH(const COutput& out, vCoins)
if(out.fSpendable)
- nBalance += out.tx->vout[out.i].nValue;
+ nBalance += out.tx->tx->vout[out.i].nValue;
return nBalance;
}
@@ -328,12 +332,12 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
}
CReserveKey *keyChange = transaction.getPossibleKeyChange();
- if(!wallet->CommitTransaction(*newTx, *keyChange))
- return TransactionCommitFailed;
+ CValidationState state;
+ if(!wallet->CommitTransaction(*newTx, *keyChange, g_connman.get(), state))
+ return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(state.GetRejectReason()));
- CTransaction* t = (CTransaction*)newTx;
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
- ssTx << *t;
+ ssTx << *newTx->tx;
transaction_array.append(&(ssTx[0]), ssTx.size());
}
@@ -531,10 +535,10 @@ WalletModel::UnlockContext WalletModel::requestUnlock()
return UnlockContext(this, valid, was_locked);
}
-WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
- wallet(wallet),
- valid(valid),
- relock(relock)
+WalletModel::UnlockContext::UnlockContext(WalletModel *_wallet, bool _valid, bool _relock):
+ wallet(_wallet),
+ valid(_valid),
+ relock(_relock)
{
}
@@ -563,6 +567,11 @@ bool WalletModel::havePrivKey(const CKeyID &address) const
return wallet->HaveKey(address);
}
+bool WalletModel::getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const
+{
+ return wallet->GetKey(address, vchPrivKeyOut);
+}
+
// returns a list of COutputs from COutPoints
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
{
@@ -572,7 +581,7 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect
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);
+ COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
vOutputs.push_back(out);
}
}
@@ -599,8 +608,8 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
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->vout.size() && wallet->IsMine(out.tx->vout[outpoint.n]) == ISMINE_SPENDABLE)
+ COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
+ if (outpoint.n < out.tx->tx->vout.size() && wallet->IsMine(out.tx->tx->vout[outpoint.n]) == ISMINE_SPENDABLE)
vCoins.push_back(out);
}
@@ -608,14 +617,14 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
{
COutput cout = out;
- while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0]))
+ 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->vin[0].prevout.hash)) break;
- cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0, true, true);
+ 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 /* depth */, true /* spendable */, true /* solvable */, true /* safe */);
}
CTxDestination address;
- if(!out.fSpendable || !ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address))
+ if(!out.fSpendable || !ExtractDestination(cout.tx->tx->vout[cout.i].scriptPubKey, address))
continue;
mapCoins[QString::fromStdString(CBitcoinAddress(address).ToString())].push_back(out);
}
@@ -683,3 +692,23 @@ bool WalletModel::abandonTransaction(uint256 hash) const
LOCK2(cs_main, wallet->cs_wallet);
return wallet->AbandonTransaction(hash);
}
+
+bool WalletModel::isWalletEnabled()
+{
+ return !GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
+}
+
+bool WalletModel::hdEnabled() const
+{
+ return wallet->IsHDEnabled();
+}
+
+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 e5470bf618..78e45dc369 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -38,8 +38,8 @@ class SendCoinsRecipient
{
public:
explicit SendCoinsRecipient() : amount(0), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) { }
- explicit SendCoinsRecipient(const QString &addr, const QString &label, const CAmount& amount, const QString &message):
- address(addr), label(label), amount(amount), message(message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {}
+ explicit SendCoinsRecipient(const QString &addr, const QString &_label, const CAmount& _amount, const QString &_message):
+ address(addr), label(_label), amount(_amount), message(_message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {}
// If from an unauthenticated payment request, this is used for storing
// the addresses, e.g. address-A<br />address-B<br />address-C.
@@ -65,7 +65,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
std::string sAddress = address.toStdString();
std::string sLabel = label.toStdString();
std::string sMessage = message.toStdString();
@@ -75,7 +75,6 @@ public:
std::string sAuthenticatedMerchant = authenticatedMerchant.toStdString();
READWRITE(this->nVersion);
- nVersion = this->nVersion;
READWRITE(sAddress);
READWRITE(sLabel);
READWRITE(amount);
@@ -145,9 +144,13 @@ public:
// Return status record for SendCoins, contains error id + information
struct SendCoinsReturn
{
- SendCoinsReturn(StatusCode status = OK):
- status(status) {}
+ SendCoinsReturn(StatusCode _status = OK, QString _reasonCommitFailed = "")
+ : status(_status),
+ reasonCommitFailed(_reasonCommitFailed)
+ {
+ }
StatusCode status;
+ QString reasonCommitFailed;
};
// prepare transaction for getting txfee before sending coins
@@ -188,6 +191,7 @@ public:
bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
bool havePrivKey(const CKeyID &address) 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;
void listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const;
@@ -203,6 +207,14 @@ public:
bool transactionCanBeAbandoned(uint256 hash) const;
bool abandonTransaction(uint256 hash) const;
+ 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 ffadf89cc8..b4445c8166 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -7,8 +7,8 @@
#include "policy/policy.h"
#include "wallet/wallet.h"
-WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &recipients) :
- recipients(recipients),
+WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) :
+ recipients(_recipients),
walletTransaction(0),
keyChange(0),
fee(0)
@@ -64,7 +64,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
if (out.amount() <= 0) continue;
if (i == nChangePosRet)
i++;
- subtotal += walletTransaction->vout[i].nValue;
+ subtotal += walletTransaction->tx->vout[i].nValue;
i++;
}
rcp.amount = subtotal;
@@ -73,7 +73,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
{
if (i == nChangePosRet)
i++;
- rcp.amount = walletTransaction->vout[i].nValue;
+ rcp.amount = walletTransaction->tx->vout[i].nValue;
i++;
}
}
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 6ce98ef160..4a18c0bd4d 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -29,11 +29,11 @@
#include <QPushButton>
#include <QVBoxLayout>
-WalletView::WalletView(const PlatformStyle *platformStyle, QWidget *parent):
+WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent):
QStackedWidget(parent),
clientModel(0),
walletModel(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
// Create tabs
overviewPage = new OverviewPage(platformStyle);
@@ -66,6 +66,7 @@ WalletView::WalletView(const PlatformStyle *platformStyle, QWidget *parent):
// Clicking on a transaction on the overview pre-selects the transaction on the transaction history page
connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex)));
+ connect(overviewPage, SIGNAL(outOfSyncWarningClicked()), this, SLOT(requestedSyncWarningInfo()));
// Double-clicking on a transaction on the transaction history page shows details
connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails()));
@@ -98,47 +99,53 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui)
// Pass through transaction notifications
connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString,QString)));
+
+ // Connect HD enabled state signal
+ connect(this, SIGNAL(hdEnabledStatusChanged(int)), gui, SLOT(setHDStatus(int)));
}
}
-void WalletView::setClientModel(ClientModel *clientModel)
+void WalletView::setClientModel(ClientModel *_clientModel)
{
- this->clientModel = clientModel;
+ this->clientModel = _clientModel;
- overviewPage->setClientModel(clientModel);
- sendCoinsPage->setClientModel(clientModel);
+ overviewPage->setClientModel(_clientModel);
+ sendCoinsPage->setClientModel(_clientModel);
}
-void WalletView::setWalletModel(WalletModel *walletModel)
+void WalletView::setWalletModel(WalletModel *_walletModel)
{
- this->walletModel = walletModel;
+ this->walletModel = _walletModel;
// Put transaction list in tabs
- transactionView->setModel(walletModel);
- overviewPage->setWalletModel(walletModel);
- receiveCoinsPage->setModel(walletModel);
- sendCoinsPage->setModel(walletModel);
- usedReceivingAddressesPage->setModel(walletModel->getAddressTableModel());
- usedSendingAddressesPage->setModel(walletModel->getAddressTableModel());
-
- if (walletModel)
+ transactionView->setModel(_walletModel);
+ overviewPage->setWalletModel(_walletModel);
+ receiveCoinsPage->setModel(_walletModel);
+ sendCoinsPage->setModel(_walletModel);
+ usedReceivingAddressesPage->setModel(_walletModel->getAddressTableModel());
+ usedSendingAddressesPage->setModel(_walletModel->getAddressTableModel());
+
+ if (_walletModel)
{
// Receive and pass through messages from wallet model
- connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int)));
+ connect(_walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int)));
// Handle changes in encryption status
- connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int)));
+ connect(_walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int)));
updateEncryptionStatus();
+ // update HD status
+ Q_EMIT hdEnabledStatusChanged(_walletModel->hdEnabled());
+
// Balloon pop-up for new transaction
- connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
+ connect(_walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(processNewTransaction(QModelIndex,int,int)));
// Ask for passphrase if needed
- connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
+ connect(_walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
// Show progress dialog
- connect(walletModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
+ connect(_walletModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
}
}
@@ -316,3 +323,8 @@ void WalletView::showProgress(const QString &title, int nProgress)
else if (progressDialog)
progressDialog->setValue(nProgress);
}
+
+void WalletView::requestedSyncWarningInfo()
+{
+ Q_EMIT outOfSyncWarningClicked();
+}
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index dbb289f425..c1f8422f0c 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -110,6 +110,9 @@ public Q_SLOTS:
/** Show progress dialog e.g. for rescan */
void showProgress(const QString &title, int nProgress);
+ /** User has requested more information about the out of sync state */
+ void requestedSyncWarningInfo();
+
Q_SIGNALS:
/** Signal that we want to show the main window */
void showNormalIfMinimized();
@@ -117,8 +120,12 @@ Q_SIGNALS:
void message(const QString &title, const QString &message, unsigned int style);
/** Encryption status of wallet changed */
void encryptionStatusChanged(int status);
+ /** HD-Enabled status of wallet changed (only possible during startup) */
+ void hdEnabledStatusChanged(int hdEnabled);
/** Notify that a new transaction appeared */
void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label);
+ /** Notify that the out of sync warning icon has been pressed */
+ void outOfSyncWarningClicked();
};
#endif // BITCOIN_QT_WALLETVIEW_H
diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp
index a11da50588..d6f40c38b8 100644
--- a/src/qt/winshutdownmonitor.cpp
+++ b/src/qt/winshutdownmonitor.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Bitcoin Core developers
+// Copyright (c) 2014-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.
diff --git a/src/random.cpp b/src/random.cpp
index d9a8cc145e..3b9df3edaa 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -11,17 +11,31 @@
#include "compat.h" // for Windows API
#include <wincrypt.h>
#endif
-#include "serialize.h" // for begin_ptr(vec)
#include "util.h" // for LogPrint()
#include "utilstrencodings.h" // for GetTime()
#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
+#ifdef HAVE_GETENTROPY
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYSCTL_ARND
+#include <sys/sysctl.h>
+#endif
+
+#include <mutex>
+
#include <openssl/err.h>
#include <openssl/rand.h>
@@ -33,15 +47,22 @@ static void RandFailure()
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;
}
void RandAddSeed()
@@ -72,16 +93,16 @@ 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, begin_ptr(vData), &nSize);
+ ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, 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
}
RegCloseKey(HKEY_PERFORMANCE_DATA);
if (ret == ERROR_SUCCESS) {
- RAND_add(begin_ptr(vData), nSize, nSize / 100.0);
- memory_cleanse(begin_ptr(vData), nSize);
- LogPrint("rand", "%s: %lu bytes\n", __func__, nSize);
+ RAND_add(vData.data(), nSize, nSize / 100.0);
+ memory_cleanse(vData.data(), nSize);
+ LogPrint(BCLog::RAND, "%s: %lu bytes\n", __func__, nSize);
} else {
static bool warned = false; // Warn only once
if (!warned) {
@@ -92,34 +113,86 @@ 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) {
+ 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);
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)
+ /* 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.
+ */
+ if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
RandFailure();
}
+#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, NULL, 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
}
@@ -130,6 +203,10 @@ void GetRandBytes(unsigned char* buf, int num)
}
}
+static std::mutex cs_rng_state;
+static unsigned char rng_state[32] = {0};
+static uint64_t rng_counter = 0;
+
void GetStrongRandBytes(unsigned char* out, int num)
{
assert(num <= 32);
@@ -145,8 +222,17 @@ void GetStrongRandBytes(unsigned char* out, int num)
GetOSRand(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);
}
@@ -178,22 +264,67 @@ uint256 GetRandHash()
return hash;
}
-uint32_t insecure_rand_Rz = 11;
-uint32_t insecure_rand_Rw = 11;
-void seed_insecure_rand(bool fDeterministic)
+void FastRandomContext::RandomSeed()
{
- // The seed values have some unlikely fixed points which we avoid.
- if (fDeterministic) {
- insecure_rand_Rz = insecure_rand_Rw = 11;
- } else {
- uint32_t tmp;
- do {
- GetRandBytes((unsigned char*)&tmp, 4);
- } while (tmp == 0 || tmp == 0x9068ffffU);
- insecure_rand_Rz = tmp;
- do {
- GetRandBytes((unsigned char*)&tmp, 4);
- } while (tmp == 0 || tmp == 0x464fffffU);
- insecure_rand_Rw = tmp;
+ uint256 seed = GetRandHash();
+ rng.SetKey(seed.begin(), 32);
+ requires_seed = false;
+}
+
+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);
}
diff --git a/src/random.h b/src/random.h
index 31b80bd565..9551e1c461 100644
--- a/src/random.h
+++ b/src/random.h
@@ -1,11 +1,13 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// 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_RANDOM_H
#define BITCOIN_RANDOM_H
+#include "crypto/chacha20.h"
+#include "crypto/common.h"
#include "uint256.h"
#include <stdint.h>
@@ -28,25 +30,101 @@ uint256 GetRandHash();
void GetStrongRandBytes(unsigned char* buf, int num);
/**
- * Seed insecure_rand using the random pool.
- * @param Deterministic Use a deterministic seed
+ * Fast randomness source. This is seeded once with secure random data, but
+ * is completely deterministic and insecure after that.
+ * This class is not thread-safe.
*/
-void seed_insecure_rand(bool fDeterministic = false);
+class FastRandomContext {
+private:
+ bool requires_seed;
+ ChaCha20 rng;
-/**
- * MWC RNG of George Marsaglia
- * This is intended to be fast. It has a period of 2^59.3, though the
- * least significant 16 bits only have a period of about 2^30.1.
- *
- * @return random value
+ 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);
+
+ /** 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;
+ }
+ }
+
+ /** 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;
+ }
+ }
+
+ /** Generate a random 32-bit integer. */
+ uint32_t rand32() { return randbits(32); }
+
+ /** 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.
*/
-extern uint32_t insecure_rand_Rz;
-extern uint32_t insecure_rand_Rw;
-static inline uint32_t insecure_rand(void)
-{
- insecure_rand_Rz = 36969 * (insecure_rand_Rz & 65535) + (insecure_rand_Rz >> 16);
- insecure_rand_Rw = 18000 * (insecure_rand_Rw & 65535) + (insecure_rand_Rw >> 16);
- return (insecure_rand_Rw << 16) + insecure_rand_Rz;
-}
+bool Random_SanityCheck();
#endif // BITCOIN_RANDOM_H
diff --git a/src/rest.cpp b/src/rest.cpp
index 2dff8d7dad..7537ed4502 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -1,14 +1,16 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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 "chain.h"
#include "chainparams.h"
+#include "core_io.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
-#include "main.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 {
@@ -50,7 +49,7 @@ struct CCoin {
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
+ inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(nTxVer);
READWRITE(nHeight);
@@ -58,14 +57,7 @@ struct CCoin {
}
};
-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 +85,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 +101,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,7 +125,7 @@ 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)
@@ -143,7 +135,7 @@ static bool rest_headers(HTTPRequest* req,
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);
@@ -169,14 +161,14 @@ static bool rest_headers(HTTPRequest* req,
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;
@@ -186,7 +178,7 @@ static bool rest_headers(HTTPRequest* req,
BOOST_FOREACH(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;
@@ -228,19 +220,19 @@ static bool rest_block(HTTPRequest* req,
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
- CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssBlock << block;
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;
@@ -274,7 +266,7 @@ static bool rest_block_notxdetails(HTTPRequest* req, const std::string& strURIPa
}
// A bit of a hack - dependency on a function defined in rpc/blockchain.cpp
-UniValue getblockchaininfo(const UniValue& params, bool fHelp);
+UniValue getblockchaininfo(const JSONRPCRequest& request);
static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
{
@@ -285,9 +277,10 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
switch (rf) {
case RF_JSON: {
- UniValue rpcParams(UniValue::VARR);
- UniValue chainInfoObject = getblockchaininfo(rpcParams, false);
- string strJSON = chainInfoObject.write() + "\n";
+ JSONRPCRequest jsonRequest;
+ jsonRequest.params = UniValue(UniValue::VARR);
+ UniValue chainInfoObject = getblockchaininfo(jsonRequest);
+ std::string strJSON = chainInfoObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
return true;
@@ -312,7 +305,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;
@@ -337,7 +330,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;
@@ -362,24 +355,24 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
if (!ParseHashStr(hashStr, hash))
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
- CTransaction tx;
+ CTransactionRef tx;
uint256 hashBlock = uint256();
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
- CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssTx << tx;
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;
@@ -387,8 +380,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;
@@ -410,7 +403,7 @@ 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);
@@ -420,11 +413,11 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// throw exception in case of a empty request
std::string strRequestMutable = req->ReadBody();
if (strRequestMutable.length() == 0 && uriParts.size() == 0)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ 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, ...
@@ -444,7 +437,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
std::string strOutput = uriParts[i].substr(uriParts[i].find("-")+1);
if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid))
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
txid.SetHex(strTxid);
vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput));
@@ -453,7 +446,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (vOutPoints.size() > 0)
fInputParsed = true;
else
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
}
switch (rf) {
@@ -469,7 +462,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (strRequestMutable.size() > 0)
{
if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Combination of URI scheme inputs and raw post data is not allowed");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Combination of URI scheme inputs and raw post data is not allowed");
CDataStream oss(SER_NETWORK, PROTOCOL_VERSION);
oss << strRequestMutable;
@@ -478,14 +471,14 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
}
} catch (const std::ios_base::failure& e) {
// abort in case of unreadable binary data
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
}
break;
}
case RF_JSON: {
if (!fInputParsed)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
break;
}
default: {
@@ -495,13 +488,14 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// limit max outpoints
if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
+ 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);
@@ -517,10 +511,11 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
for (size_t i = 0; i < vOutPoints.size(); i++) {
CCoins coins;
uint256 hash = vOutPoints[i].hash;
+ bool hit = false;
if (view.GetCoins(hash, coins)) {
mempool.pruneSpent(hash, coins);
if (coins.IsAvailable(vOutPoints[i].n)) {
- hits[i] = true;
+ hit = 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;
@@ -532,10 +527,11 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
}
}
- 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: {
@@ -543,7 +539,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);
@@ -553,7 +549,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);
@@ -578,14 +574,14 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// 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;
diff --git a/src/reverselock.h b/src/reverselock.h
index fac1ccb793..9d9cc9fd77 100644
--- a/src/reverselock.h
+++ b/src/reverselock.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -13,9 +13,9 @@ class reverse_lock
{
public:
- explicit reverse_lock(Lock& lock) : lock(lock) {
- lock.unlock();
- lock.swap(templock);
+ explicit reverse_lock(Lock& _lock) : lock(_lock) {
+ _lock.unlock();
+ _lock.swap(templock);
}
~reverse_lock() {
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 20eefa1c57..9d72a23e6d 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1,15 +1,19 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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 "rpc/blockchain.h"
+
#include "amount.h"
#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "coins.h"
#include "consensus/validation.h"
-#include "main.h"
+#include "validation.h"
+#include "core_io.h"
+#include "policy/feerate.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
#include "rpc/server.h"
@@ -26,15 +30,23 @@
#include <boost/thread/thread.hpp> // boost::thread::interrupt
-using namespace std;
+#include <mutex>
+#include <condition_variable>
+
+struct CUpdatedBlock
+{
+ uint256 hash;
+ int height;
+};
+
+static std::mutex cs_blockchange;
+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 (chainActive.Tip() == NULL)
@@ -90,7 +102,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()));
@@ -101,22 +113,22 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.push_back(Pair("confirmations", confirmations));
result.push_back(Pair("strippedsize", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
- result.push_back(Pair("cost", (int)::GetBlockCost(block)));
+ result.push_back(Pair("weight", (int)::GetBlockWeight(block)));
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion)));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
UniValue txs(UniValue::VARR);
- BOOST_FOREACH(const CTransaction&tx, block.vtx)
+ for(const auto& tx : block.vtx)
{
if(txDetails)
{
UniValue objTx(UniValue::VOBJ);
- TxToJSON(tx, uint256(), objTx);
+ TxToUniv(*tx, uint256(), objTx);
txs.push_back(objTx);
}
else
- txs.push_back(tx.GetHash().GetHex());
+ txs.push_back(tx->GetHash().GetHex());
}
result.push_back(Pair("tx", txs));
result.push_back(Pair("time", block.GetBlockTime()));
@@ -134,12 +146,12 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
return result;
}
-UniValue getblockcount(const UniValue& params, bool fHelp)
+UniValue getblockcount(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"getblockcount\n"
- "\nReturns the number of blocks in the longest block chain.\n"
+ "\nReturns the number of blocks in the longest blockchain.\n"
"\nResult:\n"
"n (numeric) The current block count\n"
"\nExamples:\n"
@@ -151,15 +163,15 @@ UniValue getblockcount(const UniValue& params, bool fHelp)
return chainActive.Height();
}
-UniValue getbestblockhash(const UniValue& params, bool fHelp)
+UniValue getbestblockhash(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"getbestblockhash\n"
- "\nReturns the hash of the best (tip) block in the longest block chain.\n"
- "\nResult\n"
+ "\nReturns the hash of the best (tip) block in the longest blockchain.\n"
+ "\nResult:\n"
"\"hex\" (string) the block hash hex encoded\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("getbestblockhash", "")
+ HelpExampleRpc("getbestblockhash", "")
);
@@ -168,10 +180,142 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp)
return chainActive.Tip()->GetBlockHash().GetHex();
}
-UniValue getdifficulty(const UniValue& params, bool fHelp)
+void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)
+{
+ if(pindex) {
+ std::lock_guard<std::mutex> lock(cs_blockchange);
+ latestblock.hash = pindex->GetBlockHash();
+ latestblock.height = pindex->nHeight;
+ }
+ cond_blockchange.notify_all();
+}
+
+UniValue waitfornewblock(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() > 1)
+ 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"
+ "\nArguments:\n"
+ "1. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
+ "\nResult:\n"
+ "{ (json object)\n"
+ " \"hash\" : { (string) The blockhash\n"
+ " \"height\" : { (int) Block height\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("waitfornewblock", "1000")
+ + HelpExampleRpc("waitfornewblock", "1000")
+ );
+ int timeout = 0;
+ if (request.params.size() > 0)
+ timeout = request.params[0].get_int();
+
+ CUpdatedBlock block;
+ {
+ std::unique_lock<std::mutex> lock(cs_blockchange);
+ block = latestblock;
+ if(timeout)
+ cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
+ else
+ cond_blockchange.wait(lock, [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
+ block = latestblock;
+ }
+ UniValue ret(UniValue::VOBJ);
+ ret.push_back(Pair("hash", block.hash.GetHex()));
+ ret.push_back(Pair("height", block.height));
+ return ret;
+}
+
+UniValue waitforblock(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ 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"
+ "\nArguments:\n"
+ "1. \"blockhash\" (required, string) Block hash to wait for.\n"
+ "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
+ "\nResult:\n"
+ "{ (json object)\n"
+ " \"hash\" : { (string) The blockhash\n"
+ " \"height\" : { (int) Block height\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
+ + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
+ );
+ int timeout = 0;
+
+ uint256 hash = uint256S(request.params[0].get_str());
+
+ if (request.params.size() > 1)
+ timeout = request.params[1].get_int();
+
+ CUpdatedBlock block;
+ {
+ std::unique_lock<std::mutex> lock(cs_blockchange);
+ if(timeout)
+ cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();});
+ else
+ cond_blockchange.wait(lock, [&hash]{return latestblock.hash == hash || !IsRPCRunning(); });
+ block = latestblock;
+ }
+
+ UniValue ret(UniValue::VOBJ);
+ ret.push_back(Pair("hash", block.hash.GetHex()));
+ ret.push_back(Pair("height", block.height));
+ return ret;
+}
+
+UniValue waitforblockheight(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ 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"
+ "\nReturns the current block on timeout or exit.\n"
+ "\nArguments:\n"
+ "1. height (required, int) Block height to wait for (int)\n"
+ "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n"
+ "\nResult:\n"
+ "{ (json object)\n"
+ " \"hash\" : { (string) The blockhash\n"
+ " \"height\" : { (int) Block height\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("waitforblockheight", "\"100\", 1000")
+ + HelpExampleRpc("waitforblockheight", "\"100\", 1000")
+ );
+ int timeout = 0;
+
+ int height = request.params[0].get_int();
+
+ if (request.params.size() > 1)
+ timeout = request.params[1].get_int();
+
+ CUpdatedBlock block;
+ {
+ std::unique_lock<std::mutex> lock(cs_blockchange);
+ if(timeout)
+ cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();});
+ else
+ cond_blockchange.wait(lock, [&height]{return latestblock.height >= height || !IsRPCRunning(); });
+ block = latestblock;
+ }
+ UniValue ret(UniValue::VOBJ);
+ ret.push_back(Pair("hash", block.hash.GetHex()));
+ ret.push_back(Pair("height", block.height));
+ return ret;
+}
+
+UniValue getdifficulty(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"getdifficulty\n"
"\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
"\nResult:\n"
@@ -187,18 +331,16 @@ UniValue getdifficulty(const UniValue& params, bool fHelp)
std::string EntryDescriptionString()
{
- return " \"size\" : n, (numeric) transaction size in bytes\n"
+ return " \"size\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n"
" \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
" \"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) priority when transaction entered pool\n"
- " \"currentpriority\" : n, (numeric) transaction priority now\n"
" \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n"
- " \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n"
+ " \"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) size of in-mempool ancestors (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"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
@@ -214,8 +356,6 @@ 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()));
@@ -223,7 +363,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
info.push_back(Pair("ancestorsize", e.GetSizeWithAncestors()));
info.push_back(Pair("ancestorfees", e.GetModFeesWithAncestors()));
const CTransaction& tx = e.GetTx();
- set<string> setDepends;
+ std::set<std::string> setDepends;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
if (mempool.exists(txin.prevout.hash))
@@ -231,7 +371,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
}
UniValue depends(UniValue::VARR);
- BOOST_FOREACH(const string& dep, setDepends)
+ BOOST_FOREACH(const std::string& dep, setDepends)
{
depends.push_back(dep);
}
@@ -239,7 +379,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
info.push_back(Pair("depends", depends));
}
-UniValue mempoolToJSON(bool fVerbose = false)
+UniValue mempoolToJSON(bool fVerbose)
{
if (fVerbose)
{
@@ -256,7 +396,7 @@ UniValue mempoolToJSON(bool fVerbose = false)
}
else
{
- vector<uint256> vtxid;
+ std::vector<uint256> vtxid;
mempool.queryHashes(vtxid);
UniValue a(UniValue::VARR);
@@ -267,14 +407,15 @@ UniValue mempoolToJSON(bool fVerbose = false)
}
}
-UniValue getrawmempool(const UniValue& params, bool fHelp)
+UniValue getrawmempool(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() > 1)
+ 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"
+ "1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
"\nResult: (for verbose = false):\n"
"[ (json array of string)\n"
" \"transactionid\" (string) The transaction id\n"
@@ -286,27 +427,27 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("getrawmempool", "true")
+ HelpExampleRpc("getrawmempool", "true")
);
bool fVerbose = false;
- if (params.size() > 0)
- fVerbose = params[0].get_bool();
+ if (request.params.size() > 0)
+ fVerbose = request.params[0].get_bool();
return mempoolToJSON(fVerbose);
}
-UniValue getmempoolancestors(const UniValue& params, bool fHelp)
+UniValue getmempoolancestors(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2) {
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ throw std::runtime_error(
"getmempoolancestors txid (verbose)\n"
"\nIf txid is in the mempool, returns all in-mempool ancestors.\n"
"\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
- "2. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
+ "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
+ "2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
"\nResult (for verbose=false):\n"
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool ancestor transaction\n"
@@ -318,17 +459,17 @@ UniValue getmempoolancestors(const UniValue& params, bool fHelp)
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("getmempoolancestors", "\"mytxid\"")
+ HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
);
}
bool fVerbose = false;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
LOCK(mempool.cs);
@@ -353,24 +494,24 @@ UniValue getmempoolancestors(const UniValue& params, bool fHelp)
UniValue o(UniValue::VOBJ);
BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors) {
const CTxMemPoolEntry &e = *ancestorIt;
- const uint256& hash = e.GetTx().GetHash();
+ const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
entryToJSON(info, e);
- o.push_back(Pair(hash.ToString(), info));
+ o.push_back(Pair(_hash.ToString(), info));
}
return o;
}
}
-UniValue getmempooldescendants(const UniValue& params, bool fHelp)
+UniValue getmempooldescendants(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2) {
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ throw std::runtime_error(
"getmempooldescendants txid (verbose)\n"
"\nIf txid is in the mempool, returns all in-mempool descendants.\n"
"\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
- "2. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
+ "1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
+ "2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
"\nResult (for verbose=false):\n"
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool descendant transaction\n"
@@ -382,17 +523,17 @@ UniValue getmempooldescendants(const UniValue& params, bool fHelp)
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("getmempooldescendants", "\"mytxid\"")
+ HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
);
}
bool fVerbose = false;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
LOCK(mempool.cs);
@@ -417,19 +558,19 @@ UniValue getmempooldescendants(const UniValue& params, bool fHelp)
UniValue o(UniValue::VOBJ);
BOOST_FOREACH(CTxMemPool::txiter descendantIt, setDescendants) {
const CTxMemPoolEntry &e = *descendantIt;
- const uint256& hash = e.GetTx().GetHash();
+ const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
entryToJSON(info, e);
- o.push_back(Pair(hash.ToString(), info));
+ o.push_back(Pair(_hash.ToString(), info));
}
return o;
}
}
-UniValue getmempoolentry(const UniValue& params, bool fHelp)
+UniValue getmempoolentry(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1) {
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1) {
+ throw std::runtime_error(
"getmempoolentry txid\n"
"\nReturns mempool data for given transaction\n"
"\nArguments:\n"
@@ -438,13 +579,13 @@ UniValue getmempoolentry(const UniValue& params, bool fHelp)
"{ (json object)\n"
+ EntryDescriptionString()
+ "}\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("getmempoolentry", "\"mytxid\"")
+ HelpExampleRpc("getmempoolentry", "\"mytxid\"")
);
}
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
LOCK(mempool.cs);
@@ -459,14 +600,14 @@ UniValue getmempoolentry(const UniValue& params, bool fHelp)
return info;
}
-UniValue getblockhash(const UniValue& params, bool fHelp)
+UniValue getblockhash(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "getblockhash index\n"
- "\nReturns hash of block in best-block-chain at index provided.\n"
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
+ "getblockhash height\n"
+ "\nReturns hash of block in best-block-chain at height provided.\n"
"\nArguments:\n"
- "1. index (numeric, required) The block index\n"
+ "1. height (numeric, required) The height index\n"
"\nResult:\n"
"\"hash\" (string) The block hash\n"
"\nExamples:\n"
@@ -476,7 +617,7 @@ UniValue getblockhash(const UniValue& params, bool fHelp)
LOCK(cs_main);
- int nHeight = params[0].get_int();
+ int nHeight = request.params[0].get_int();
if (nHeight < 0 || nHeight > chainActive.Height())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
@@ -484,10 +625,10 @@ UniValue getblockhash(const UniValue& params, bool fHelp)
return pblockindex->GetBlockHash().GetHex();
}
-UniValue getblockheader(const UniValue& params, bool fHelp)
+UniValue getblockheader(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ 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"
@@ -507,9 +648,9 @@ UniValue getblockheader(const UniValue& params, bool fHelp)
" \"nonce\" : n, (numeric) The nonce\n"
" \"bits\" : \"1d00ffff\", (string) The bits\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\n"
+ " \"chainwork\" : \"0000...1f3\" (string) Expected number of hashes required to produce the current chain (in hex)\n"
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\", (string) The hash of the next block\n"
- " \"chainwork\" : \"0000...1f3\" (string) Expected number of hashes required to produce the current chain (in hex)\n"
"}\n"
"\nResult (for verbose=false):\n"
"\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
@@ -520,12 +661,12 @@ UniValue getblockheader(const UniValue& params, bool fHelp)
LOCK(cs_main);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
bool fVerbose = true;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
@@ -543,23 +684,26 @@ UniValue getblockheader(const UniValue& params, bool fHelp)
return blockheaderToJSON(pblockindex);
}
-UniValue getblock(const UniValue& params, bool fHelp)
+UniValue getblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
- "getblock \"hash\" ( 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"
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ 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. \"hash\" (string, required) The block hash\n"
- "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"
- "\nResult (for verbose = true):\n"
+ "1. \"blockhash\" (string, required) The block hash\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"
" \"size\" : n, (numeric) The block size\n"
" \"strippedsize\" : n, (numeric) The block size excluding witness data\n"
- " \"cost\" : n (numeric) The block cost\n"
+ " \"weight\" : n (numeric) The block weight as defined in BIP 141\n"
" \"height\" : n, (numeric) The block height or index\n"
" \"version\" : n, (numeric) The block version\n"
" \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n"
@@ -577,8 +721,14 @@ UniValue getblock(const UniValue& params, bool fHelp)
" \"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\"")
@@ -586,12 +736,16 @@ UniValue getblock(const UniValue& params, bool fHelp)
LOCK(cs_main);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
- bool fVerbose = true;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ int verbosity = 1;
+ if (request.params.size() > 1) {
+ 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");
@@ -600,20 +754,25 @@ UniValue getblock(const UniValue& params, bool fHelp)
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);
+ CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssBlock << block;
std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
return strHex;
}
- return blockToJSON(block, pblockindex);
+ return blockToJSON(block, pblockindex, verbosity >= 2);
}
struct CCoinsStats
@@ -632,7 +791,7 @@ struct CCoinsStats
//! Calculate statistics about the unspent transaction output set
static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
{
- boost::scoped_ptr<CCoinsViewCursor> pcursor(view->Cursor());
+ std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
stats.hashBlock = pcursor->GetBestBlock();
@@ -670,10 +829,59 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
return true;
}
-UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
+UniValue pruneblockchain(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 1)
+ 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 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"
+ + HelpExampleCli("pruneblockchain", "1000")
+ + HelpExampleRpc("pruneblockchain", "1000"));
+
+ if (!fPruneMode)
+ throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
+
+ LOCK(cs_main);
+
+ int heightParam = request.params[0].get_int();
+ if (heightParam < 0)
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height.");
+
+ // 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) {
+ // 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_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
+ }
+ heightParam = pindex->nHeight;
+ }
+
+ unsigned int height = (unsigned int) heightParam;
+ unsigned int chainHeight = (unsigned int) chainActive.Height();
+ if (chainHeight < Params().PruneAfterHeight())
+ 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(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.");
+ height = chainHeight - MIN_BLOCKS_TO_KEEP;
+ }
+
+ PruneBlockFilesManual(height);
+ return uint64_t(height);
+}
+
+UniValue gettxoutsetinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"gettxoutsetinfo\n"
"\nReturns statistics about the unspent transaction output set.\n"
"Note this call may take some time.\n"
@@ -704,20 +912,22 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize));
ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex()));
ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount)));
+ } else {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
}
return ret;
}
-UniValue gettxout(const UniValue& params, bool fHelp)
+UniValue gettxout(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
- throw runtime_error(
- "gettxout \"txid\" n ( includemempool )\n"
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
+ 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. includemempool (boolean, optional) Whether to include the mem pool\n"
+ "3. include_mempool (boolean, optional) Whether to include the mempool\n"
"\nResult:\n"
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
@@ -729,7 +939,7 @@ UniValue gettxout(const UniValue& params, bool fHelp)
" \"reqSigs\" : n, (numeric) Number of required signatures\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n"
" \"addresses\" : [ (array of string) array of bitcoin addresses\n"
- " \"bitcoinaddress\" (string) bitcoin address\n"
+ " \"address\" (string) bitcoin address\n"
" ,...\n"
" ]\n"
" },\n"
@@ -750,12 +960,12 @@ UniValue gettxout(const UniValue& params, bool fHelp)
UniValue ret(UniValue::VOBJ);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
- int n = params[1].get_int();
+ int n = request.params[1].get_int();
bool fMempool = true;
- if (params.size() > 2)
- fMempool = params[2].get_bool();
+ if (request.params.size() > 2)
+ fMempool = request.params[2].get_bool();
CCoins coins;
if (fMempool) {
@@ -780,7 +990,7 @@ UniValue gettxout(const UniValue& params, bool fHelp)
ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
UniValue o(UniValue::VOBJ);
- ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
+ ScriptPubKeyToUniv(coins.vout[n].scriptPubKey, o, true);
ret.push_back(Pair("scriptPubKey", o));
ret.push_back(Pair("version", coins.nVersion));
ret.push_back(Pair("coinbase", coins.fCoinBase));
@@ -788,17 +998,17 @@ UniValue gettxout(const UniValue& params, bool fHelp)
return ret;
}
-UniValue verifychain(const UniValue& params, bool fHelp)
+UniValue verifychain(const JSONRPCRequest& request)
{
int nCheckLevel = GetArg("-checklevel", DEFAULT_CHECKLEVEL);
int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
- if (fHelp || params.size() > 2)
- throw runtime_error(
- "verifychain ( checklevel numblocks )\n"
+ if (request.fHelp || request.params.size() > 2)
+ throw std::runtime_error(
+ "verifychain ( checklevel nblocks )\n"
"\nVerifies blockchain database.\n"
"\nArguments:\n"
"1. checklevel (numeric, optional, 0-4, default=" + strprintf("%d", nCheckLevel) + ") How thorough the block verification is.\n"
- "2. numblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n"
+ "2. nblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n"
"\nResult:\n"
"true|false (boolean) Verified or not\n"
"\nExamples:\n"
@@ -808,31 +1018,32 @@ UniValue verifychain(const UniValue& params, bool fHelp)
LOCK(cs_main);
- if (params.size() > 0)
- nCheckLevel = params[0].get_int();
- if (params.size() > 1)
- nCheckDepth = params[1].get_int();
+ if (request.params.size() > 0)
+ nCheckLevel = request.params[0].get_int();
+ if (request.params.size() > 1)
+ nCheckDepth = request.params[1].get_int();
return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth);
}
/** Implementation of IsSuperMajority with better feedback */
-static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams)
+static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
{
- int nFound = 0;
- CBlockIndex* pstart = pindex;
- for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++)
+ UniValue rv(UniValue::VOBJ);
+ bool activated = false;
+ switch(version)
{
- if (pstart->nVersion >= minVersion)
- ++nFound;
- pstart = pstart->pprev;
+ case 2:
+ activated = pindex->nHeight >= consensusParams.BIP34Height;
+ break;
+ case 3:
+ activated = pindex->nHeight >= consensusParams.BIP66Height;
+ break;
+ case 4:
+ activated = pindex->nHeight >= consensusParams.BIP65Height;
+ break;
}
-
- UniValue rv(UniValue::VOBJ);
- rv.push_back(Pair("status", nFound >= nRequired));
- rv.push_back(Pair("found", nFound));
- rv.push_back(Pair("required", nRequired));
- rv.push_back(Pair("window", consensusParams.nMajorityWindow));
+ rv.push_back(Pair("status", activated));
return rv;
}
@@ -841,8 +1052,7 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex*
UniValue rv(UniValue::VOBJ);
rv.push_back(Pair("id", name));
rv.push_back(Pair("version", version));
- rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)));
- rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityRejectBlockOutdated, consensusParams)));
+ rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams)));
return rv;
}
@@ -863,6 +1073,7 @@ 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)));
return rv;
}
@@ -875,12 +1086,12 @@ void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const std::string &name,
bip9_softforks.push_back(Pair(name, BIP9SoftForkDesc(consensusParams, id)));
}
-UniValue getblockchaininfo(const UniValue& params, bool fHelp)
+UniValue getblockchaininfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"getblockchaininfo\n"
- "Returns an object containing various state info regarding block chain processing.\n"
+ "Returns an object containing various state info regarding blockchain processing.\n"
"\nResult:\n"
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
@@ -892,18 +1103,14 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
" \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
" \"pruned\": xx, (boolean) if the blocks are subject to pruning\n"
- " \"pruneheight\": xxxxxx, (numeric) heighest block available\n"
+ " \"pruneheight\": xxxxxx, (numeric) lowest-height complete block stored\n"
" \"softforks\": [ (array) status of softforks in progress\n"
" {\n"
" \"id\": \"xxxx\", (string) name of softfork\n"
" \"version\": xx, (numeric) block version\n"
- " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n"
+ " \"reject\": { (object) progress toward rejecting pre-softfork blocks\n"
" \"status\": xx, (boolean) true if threshold reached\n"
- " \"found\": xx, (numeric) number of blocks with the new version found\n"
- " \"required\": xx, (numeric) number of blocks required to trigger\n"
- " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n"
" },\n"
- " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
" }, ...\n"
" ],\n"
" \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n"
@@ -911,7 +1118,8 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n"
" \"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"
+ " \"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"
" }\n"
" }\n"
"}\n"
@@ -929,7 +1137,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast()));
- obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip())));
+ obj.push_back(Pair("verificationprogress", GuessVerificationProgress(Params().TxData(), chainActive.Tip())));
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
obj.push_back(Pair("pruned", fPruneMode));
@@ -971,10 +1179,10 @@ struct CompareBlocksByHeight
}
};
-UniValue getchaintips(const UniValue& params, bool fHelp)
+UniValue getchaintips(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ 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"
@@ -1007,7 +1215,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
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.
@@ -1046,7 +1254,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
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";
@@ -1087,16 +1295,16 @@ UniValue mempoolInfoToJSON()
return ret;
}
-UniValue getmempoolinfo(const UniValue& params, bool fHelp)
+UniValue getmempoolinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"getmempoolinfo\n"
"\nReturns details on the active state of the TX memory pool.\n"
"\nResult:\n"
"{\n"
" \"size\": xxxxx, (numeric) Current tx count\n"
- " \"bytes\": xxxxx, (numeric) Sum of all tx sizes\n"
+ " \"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"
@@ -1109,21 +1317,59 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp)
return mempoolInfoToJSON();
}
-UniValue invalidateblock(const UniValue& params, bool fHelp)
+UniValue preciousblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "invalidateblock \"hash\"\n"
+ if (request.fHelp || request.params.size() != 1)
+ 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"
+ "\nThe effects of preciousblock are not retained across restarts.\n"
+ "\nArguments:\n"
+ "1. \"blockhash\" (string, required) the hash of the block to mark as precious\n"
+ "\nResult:\n"
+ "\nExamples:\n"
+ + HelpExampleCli("preciousblock", "\"blockhash\"")
+ + HelpExampleRpc("preciousblock", "\"blockhash\"")
+ );
+
+ std::string strHash = request.params[0].get_str();
+ uint256 hash(uint256S(strHash));
+ CBlockIndex* pblockindex;
+
+ {
+ LOCK(cs_main);
+ if (mapBlockIndex.count(hash) == 0)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+
+ pblockindex = mapBlockIndex[hash];
+ }
+
+ CValidationState state;
+ PreciousBlock(state, Params(), pblockindex);
+
+ if (!state.IsValid()) {
+ throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
+ }
+
+ return NullUniValue;
+}
+
+UniValue invalidateblock(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
+ "invalidateblock \"blockhash\"\n"
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"
"\nArguments:\n"
- "1. hash (string, required) the hash of the block to mark as invalid\n"
+ "1. \"blockhash\" (string, required) the hash of the block to mark as invalid\n"
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("invalidateblock", "\"blockhash\"")
+ HelpExampleRpc("invalidateblock", "\"blockhash\"")
);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
CValidationState state;
@@ -1147,22 +1393,22 @@ UniValue invalidateblock(const UniValue& params, bool fHelp)
return NullUniValue;
}
-UniValue reconsiderblock(const UniValue& params, bool fHelp)
+UniValue reconsiderblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "reconsiderblock \"hash\"\n"
+ if (request.fHelp || request.params.size() != 1)
+ 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"
"\nArguments:\n"
- "1. hash (string, required) the hash of the block to reconsider\n"
+ "1. \"blockhash\" (string, required) the hash of the block to reconsider\n"
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("reconsiderblock", "\"blockhash\"")
+ HelpExampleRpc("reconsiderblock", "\"blockhash\"")
);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
{
@@ -1184,33 +1430,105 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
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 statistics in UNIX format.\n"
+ " \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n"
+ " \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window.\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
+
+ if (request.params.size() > 0 && !request.params[0].isNull()) {
+ blockcount = request.params[0].get_int();
+ }
+
+ bool havehash = request.params.size() > 1 && !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();
+ }
+ }
+
+ if (blockcount < 1 || blockcount >= pindex->nHeight) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 1 and the block's height");
+ }
+
+ 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("txrate", ((double)nTxDiff) / nTimeDiff));
+
+ return ret;
+}
+
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
- // --------------------- ------------------------ ----------------------- ----------
- { "blockchain", "getblockchaininfo", &getblockchaininfo, true },
- { "blockchain", "getbestblockhash", &getbestblockhash, true },
- { "blockchain", "getblockcount", &getblockcount, true },
- { "blockchain", "getblock", &getblock, true },
- { "blockchain", "getblockhash", &getblockhash, true },
- { "blockchain", "getblockheader", &getblockheader, true },
- { "blockchain", "getchaintips", &getchaintips, true },
- { "blockchain", "getdifficulty", &getdifficulty, true },
- { "blockchain", "getmempoolancestors", &getmempoolancestors, true },
- { "blockchain", "getmempooldescendants", &getmempooldescendants, true },
- { "blockchain", "getmempoolentry", &getmempoolentry, true },
- { "blockchain", "getmempoolinfo", &getmempoolinfo, true },
- { "blockchain", "getrawmempool", &getrawmempool, true },
- { "blockchain", "gettxout", &gettxout, true },
- { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
- { "blockchain", "verifychain", &verifychain, true },
+{ // category name actor (function) okSafe argNames
+ // --------------------- ------------------------ ----------------------- ------ ----------
+ { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} },
+ { "blockchain", "getchaintxstats", &getchaintxstats, true, {"nblocks", "blockhash"} },
+ { "blockchain", "getbestblockhash", &getbestblockhash, true, {} },
+ { "blockchain", "getblockcount", &getblockcount, true, {} },
+ { "blockchain", "getblock", &getblock, true, {"blockhash","verbosity|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"} },
/* Not shown in help */
- { "hidden", "invalidateblock", &invalidateblock, true },
- { "hidden", "reconsiderblock", &reconsiderblock, true },
+ { "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"} },
};
-void RegisterBlockchainRPCCommands(CRPCTable &tableRPC)
+void RegisterBlockchainRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
new file mode 100644
index 0000000000..c021441b0a
--- /dev/null
+++ b/src/rpc/blockchain.h
@@ -0,0 +1,40 @@
+// 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 CScript;
+class CTransaction;
+class uint256;
+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 d0675fdb49..df017d89cb 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -13,103 +13,129 @@
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <univalue.h>
-using namespace std;
-
class CRPCConvertParam
{
public:
std::string methodName; //!< method whose params want conversion
int paramIdx; //!< 0-based idx of param to convert
+ std::string paramName; //!< parameter name
};
+/**
+ * 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.
+ */
static const CRPCConvertParam vRPCConvertParams[] =
{
- { "stop", 0 },
- { "setmocktime", 0 },
- { "getaddednodeinfo", 0 },
- { "generate", 0 },
- { "generate", 1 },
- { "generatetoaddress", 0 },
- { "generatetoaddress", 2 },
- { "getnetworkhashps", 0 },
- { "getnetworkhashps", 1 },
- { "sendtoaddress", 1 },
- { "sendtoaddress", 4 },
- { "settxfee", 0 },
- { "getreceivedbyaddress", 1 },
- { "getreceivedbyaccount", 1 },
- { "listreceivedbyaddress", 0 },
- { "listreceivedbyaddress", 1 },
- { "listreceivedbyaddress", 2 },
- { "listreceivedbyaccount", 0 },
- { "listreceivedbyaccount", 1 },
- { "listreceivedbyaccount", 2 },
- { "getbalance", 1 },
- { "getbalance", 2 },
- { "getblockhash", 0 },
- { "move", 2 },
- { "move", 3 },
- { "sendfrom", 2 },
- { "sendfrom", 3 },
- { "listtransactions", 1 },
- { "listtransactions", 2 },
- { "listtransactions", 3 },
- { "listaccounts", 0 },
- { "listaccounts", 1 },
- { "walletpassphrase", 1 },
- { "getblocktemplate", 0 },
- { "listsinceblock", 1 },
- { "listsinceblock", 2 },
- { "sendmany", 1 },
- { "sendmany", 2 },
- { "sendmany", 4 },
- { "addmultisigaddress", 0 },
- { "addmultisigaddress", 1 },
- { "createmultisig", 0 },
- { "createmultisig", 1 },
- { "listunspent", 0 },
- { "listunspent", 1 },
- { "listunspent", 2 },
- { "getblock", 1 },
- { "getblockheader", 1 },
- { "gettransaction", 1 },
- { "getrawtransaction", 1 },
- { "createrawtransaction", 0 },
- { "createrawtransaction", 1 },
- { "createrawtransaction", 2 },
- { "signrawtransaction", 1 },
- { "signrawtransaction", 2 },
- { "sendrawtransaction", 1 },
- { "fundrawtransaction", 1 },
- { "gettxout", 1 },
- { "gettxout", 2 },
- { "gettxoutproof", 0 },
- { "lockunspent", 0 },
- { "lockunspent", 1 },
- { "importprivkey", 2 },
- { "importaddress", 2 },
- { "importaddress", 3 },
- { "importpubkey", 2 },
- { "verifychain", 0 },
- { "verifychain", 1 },
- { "keypoolrefill", 0 },
- { "getrawmempool", 0 },
- { "estimatefee", 0 },
- { "estimatepriority", 0 },
- { "estimatesmartfee", 0 },
- { "estimatesmartpriority", 0 },
- { "prioritisetransaction", 1 },
- { "prioritisetransaction", 2 },
- { "setban", 2 },
- { "setban", 3 },
- { "getmempoolancestors", 1 },
- { "getmempooldescendants", 1 },
+ { "setmocktime", 0, "timestamp" },
+ { "generate", 0, "nblocks" },
+ { "generate", 1, "maxtries" },
+ { "generatetoaddress", 0, "nblocks" },
+ { "generatetoaddress", 2, "maxtries" },
+ { "getnetworkhashps", 0, "nblocks" },
+ { "getnetworkhashps", 1, "height" },
+ { "sendtoaddress", 1, "amount" },
+ { "sendtoaddress", 4, "subtractfeefromamount" },
+ { "settxfee", 0, "amount" },
+ { "getreceivedbyaddress", 1, "minconf" },
+ { "getreceivedbyaccount", 1, "minconf" },
+ { "listreceivedbyaddress", 0, "minconf" },
+ { "listreceivedbyaddress", 1, "include_empty" },
+ { "listreceivedbyaddress", 2, "include_watchonly" },
+ { "listreceivedbyaccount", 0, "minconf" },
+ { "listreceivedbyaccount", 1, "include_empty" },
+ { "listreceivedbyaccount", 2, "include_watchonly" },
+ { "getbalance", 1, "minconf" },
+ { "getbalance", 2, "include_watchonly" },
+ { "getblockhash", 0, "height" },
+ { "waitforblockheight", 0, "height" },
+ { "waitforblockheight", 1, "timeout" },
+ { "waitforblock", 1, "timeout" },
+ { "waitfornewblock", 0, "timeout" },
+ { "move", 2, "amount" },
+ { "move", 3, "minconf" },
+ { "sendfrom", 2, "amount" },
+ { "sendfrom", 3, "minconf" },
+ { "listtransactions", 1, "count" },
+ { "listtransactions", 2, "skip" },
+ { "listtransactions", 3, "include_watchonly" },
+ { "listaccounts", 0, "minconf" },
+ { "listaccounts", 1, "include_watchonly" },
+ { "walletpassphrase", 1, "timeout" },
+ { "getblocktemplate", 0, "template_request" },
+ { "listsinceblock", 1, "target_confirmations" },
+ { "listsinceblock", 2, "include_watchonly" },
+ { "sendmany", 1, "amounts" },
+ { "sendmany", 2, "minconf" },
+ { "sendmany", 4, "subtractfeefrom" },
+ { "addmultisigaddress", 0, "nrequired" },
+ { "addmultisigaddress", 1, "keys" },
+ { "createmultisig", 0, "nrequired" },
+ { "createmultisig", 1, "keys" },
+ { "listunspent", 0, "minconf" },
+ { "listunspent", 1, "maxconf" },
+ { "listunspent", 2, "addresses" },
+ { "listunspent", 4, "query_options" },
+ { "getblock", 1, "verbosity" },
+ { "getblockheader", 1, "verbose" },
+ { "getchaintxstats", 0, "nblocks" },
+ { "gettransaction", 1, "include_watchonly" },
+ { "getrawtransaction", 1, "verbose" },
+ { "createrawtransaction", 0, "inputs" },
+ { "createrawtransaction", 1, "outputs" },
+ { "createrawtransaction", 2, "locktime" },
+ { "signrawtransaction", 1, "prevtxs" },
+ { "signrawtransaction", 2, "privkeys" },
+ { "sendrawtransaction", 1, "allowhighfees" },
+ { "fundrawtransaction", 1, "options" },
+ { "gettxout", 1, "n" },
+ { "gettxout", 2, "include_mempool" },
+ { "gettxoutproof", 0, "txids" },
+ { "lockunspent", 0, "unlock" },
+ { "lockunspent", 1, "transactions" },
+ { "importprivkey", 2, "rescan" },
+ { "importaddress", 2, "rescan" },
+ { "importaddress", 3, "p2sh" },
+ { "importpubkey", 2, "rescan" },
+ { "importmulti", 0, "requests" },
+ { "importmulti", 1, "options" },
+ { "verifychain", 0, "checklevel" },
+ { "verifychain", 1, "nblocks" },
+ { "pruneblockchain", 0, "height" },
+ { "keypoolrefill", 0, "newsize" },
+ { "getrawmempool", 0, "verbose" },
+ { "estimatefee", 0, "nblocks" },
+ { "estimatesmartfee", 0, "nblocks" },
+ { "prioritisetransaction", 1, "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" },
+ // Echo with conversion (For testing only)
+ { "echojson", 0, "arg0" },
+ { "echojson", 1, "arg1" },
+ { "echojson", 2, "arg2" },
+ { "echojson", 3, "arg3" },
+ { "echojson", 4, "arg4" },
+ { "echojson", 5, "arg5" },
+ { "echojson", 6, "arg6" },
+ { "echojson", 7, "arg7" },
+ { "echojson", 8, "arg8" },
+ { "echojson", 9, "arg9" },
};
class CRPCConvertTable
{
private:
- std::set<std::pair<std::string, int> > members;
+ std::set<std::pair<std::string, int>> members;
+ std::set<std::pair<std::string, std::string>> membersByName;
public:
CRPCConvertTable();
@@ -117,6 +143,9 @@ public:
bool convert(const std::string& method, int idx) {
return (members.count(std::make_pair(method, idx)) > 0);
}
+ bool convert(const std::string& method, const std::string& name) {
+ return (membersByName.count(std::make_pair(method, name)) > 0);
+ }
};
CRPCConvertTable::CRPCConvertTable()
@@ -127,6 +156,8 @@ CRPCConvertTable::CRPCConvertTable()
for (unsigned int i = 0; i < n_elem; i++) {
members.insert(std::make_pair(vRPCConvertParams[i].methodName,
vRPCConvertParams[i].paramIdx));
+ membersByName.insert(std::make_pair(vRPCConvertParams[i].methodName,
+ vRPCConvertParams[i].paramName));
}
}
@@ -140,11 +171,10 @@ 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];
}
-/** Convert strings to command-specific RPC representation */
UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
{
UniValue params(UniValue::VARR);
@@ -163,3 +193,28 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s
return params;
}
+
+UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams)
+{
+ UniValue params(UniValue::VOBJ);
+
+ for (const std::string &s: strParams) {
+ size_t pos = s.find("=");
+ if (pos == std::string::npos) {
+ throw(std::runtime_error("No '=' in named argument '"+s+"', this needs to be present for every argument (even if it is empty)"));
+ }
+
+ std::string name = s.substr(0, pos);
+ std::string value = s.substr(pos+1);
+
+ if (!rpcCvtTable.convert(strMethod, name)) {
+ // insert string value directly
+ params.pushKV(name, value);
+ } else {
+ // parse string as JSON, insert bool/number/object/etc. value
+ params.pushKV(name, ParseNonRFCJSONValue(value));
+ }
+ }
+
+ return params;
+}
diff --git a/src/rpc/client.h b/src/rpc/client.h
index ae015860b6..e7cf035d8f 100644
--- a/src/rpc/client.h
+++ b/src/rpc/client.h
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -8,7 +8,12 @@
#include <univalue.h>
+/** Convert positional arguments to command-specific RPC representation */
UniValue RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);
+
+/** Convert named arguments to command-specific RPC representation */
+UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector<std::string>& strParams);
+
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
* as well as objects and arrays.
*/
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 4c4e599781..4ce52a6c7f 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -12,25 +12,25 @@
#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
-#include "main.h"
+#include "validation.h"
#include "miner.h"
#include "net.h"
+#include "policy/fees.h"
#include "pow.h"
+#include "rpc/blockchain.h"
#include "rpc/server.h"
#include "txmempool.h"
#include "util.h"
#include "utilstrencodings.h"
#include "validationinterface.h"
+#include <memory>
#include <stdint.h>
#include <boost/assign/list_of.hpp>
-#include <boost/shared_ptr.hpp>
#include <univalue.h>
-using namespace std;
-
/**
* Return average network hashes per second based on the last 'lookup' blocks,
* or from the last difficulty change if 'lookup' is nonpositive.
@@ -73,17 +73,17 @@ UniValue GetNetworkHashPS(int lookup, int height) {
return workDiff.getdouble() / timeDiff;
}
-UniValue getnetworkhashps(const UniValue& params, bool fHelp)
+UniValue getnetworkhashps(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 2)
- throw runtime_error(
- "getnetworkhashps ( blocks height )\n"
+ if (request.fHelp || request.params.size() > 2)
+ 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"
"Pass in [height] to estimate the network speed at the time when a certain block was found.\n"
"\nArguments:\n"
- "1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n"
- "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n"
+ "1. nblocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n"
+ "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n"
"\nResult:\n"
"x (numeric) Hashes per second estimated\n"
"\nExamples:\n"
@@ -92,10 +92,10 @@ UniValue getnetworkhashps(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
+ return GetNetworkHashPS(request.params.size() > 0 ? request.params[0].get_int() : 120, request.params.size() > 1 ? 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;
@@ -130,8 +130,8 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
if (pblock->nNonce == nInnerLoopCount) {
continue;
}
- CValidationState state;
- if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL))
+ std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
+ if (!ProcessNewBlock(Params(), shared_pblock, true, NULL))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
@@ -145,29 +145,29 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
return blockHashes;
}
-UniValue generate(const UniValue& params, bool fHelp)
+UniValue generate(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
- "generate numblocks ( maxtries )\n"
- "\nMine up to numblocks blocks immediately (before the RPC call returns)\n"
+ 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)\n"
"\nArguments:\n"
- "1. numblocks (numeric, required) How many blocks are generated immediately.\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"
+ "\nResult:\n"
"[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
"\nGenerate 11 blocks\n"
+ HelpExampleCli("generate", "11")
);
- int nGenerate = params[0].get_int();
+ int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
- if (params.size() > 1) {
- nMaxTries = params[1].get_int();
+ if (request.params.size() > 1) {
+ nMaxTries = request.params[1].get_int();
}
- boost::shared_ptr<CReserveScript> coinbaseScript;
+ std::shared_ptr<CReserveScript> coinbaseScript;
GetMainSignals().ScriptForMining(coinbaseScript);
// If the keypool is exhausted, no script is returned at all. Catch this.
@@ -181,56 +181,56 @@ UniValue generate(const UniValue& params, bool fHelp)
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true);
}
-UniValue generatetoaddress(const UniValue& params, bool fHelp)
+UniValue generatetoaddress(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
- throw runtime_error(
- "generatetoaddress numblocks address (maxtries)\n"
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
+ throw std::runtime_error(
+ "generatetoaddress nblocks address (maxtries)\n"
"\nMine blocks immediately to a specified address (before the RPC call returns)\n"
"\nArguments:\n"
- "1. numblocks (numeric, required) How many blocks are generated immediately.\n"
- "2. address (string, required) The address to send the newly generated bitcoin to.\n"
+ "1. nblocks (numeric, required) How many blocks are generated immediately.\n"
+ "2. address (string, required) The address to send the newly generated bitcoin to.\n"
"3. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
- "\nResult\n"
+ "\nResult:\n"
"[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
"\nGenerate 11 blocks to myaddress\n"
+ HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
);
- int nGenerate = params[0].get_int();
+ int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
- if (params.size() > 2) {
- nMaxTries = params[2].get_int();
+ if (request.params.size() > 2) {
+ nMaxTries = request.params[2].get_int();
}
- CBitcoinAddress address(params[1].get_str());
+ CBitcoinAddress address(request.params[1].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
-
- boost::shared_ptr<CReserveScript> coinbaseScript(new CReserveScript());
+
+ std::shared_ptr<CReserveScript> coinbaseScript = std::make_shared<CReserveScript>();
coinbaseScript->reserveScript = GetScriptForDestination(address.Get());
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
}
-UniValue getmininginfo(const UniValue& params, bool fHelp)
+UniValue getmininginfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ 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"
- " \"currentblockcost\": nnn, (numeric) The last block cost\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"
- " \"pooledtx\": n (numeric) The size of the mem pool\n"
- " \"testnet\": true|false (boolean) If using testnet or not\n"
- " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\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"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmininginfo", "")
@@ -243,46 +243,42 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
- obj.push_back(Pair("currentblockcost", (uint64_t)nLastBlockCost));
+ 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(params, false)));
+ obj.push_back(Pair("networkhashps", getnetworkhashps(request)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
- obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
return obj;
}
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
-UniValue prioritisetransaction(const UniValue& params, bool fHelp)
+UniValue prioritisetransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 3)
- throw runtime_error(
- "prioritisetransaction <txid> <priority delta> <fee delta>\n"
+ if (request.fHelp || request.params.size() != 2)
+ throw std::runtime_error(
+ "prioritisetransaction <txid> <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"
- "3. fee delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n"
+ "2. 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"
- "\nResult\n"
+ "\nResult:\n"
"true (boolean) Returns true\n"
"\nExamples:\n"
- + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
- + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
+ + HelpExampleCli("prioritisetransaction", "\"txid\" 10000")
+ + HelpExampleRpc("prioritisetransaction", "\"txid\", 10000")
);
LOCK(cs_main);
- uint256 hash = ParseHashStr(params[0].get_str(), "txid");
- CAmount nAmount = params[2].get_int64();
+ uint256 hash = ParseHashStr(request.params[0].get_str(), "txid");
+ CAmount nAmount = request.params[1].get_int64();
- mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount);
+ mempool.PrioritiseTransaction(hash, nAmount);
return true;
}
@@ -315,71 +311,77 @@ std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
return s;
}
-UniValue getblocktemplate(const UniValue& params, bool fHelp)
+UniValue getblocktemplate(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 1)
- throw runtime_error(
- "getblocktemplate ( \"jsonrequestobject\" )\n"
+ if (request.fHelp || request.params.size() > 1)
+ 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"
- "For full specification, see BIPs 22 and 9:\n"
+ "For full specification, see BIPs 22, 23, 9, and 145:\n"
" https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n"
+ " https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n"
" https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
+ " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n"
"\nArguments:\n"
- "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n"
+ "1. template_request (json object, optional) A json object in the following spec\n"
" {\n"
- " \"mode\":\"template\" (string, optional) This must be set to \"template\" or omitted\n"
- " \"capabilities\":[ (array, optional) A list of strings\n"
- " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n"
+ " \"mode\":\"template\" (string, optional) This must be set to \"template\", \"proposal\" (see BIP 23), or omitted\n"
+ " \"capabilities\":[ (array, optional) A list of strings\n"
+ " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n"
" ,...\n"
- " ]\n"
+ " ],\n"
+ " \"rules\":[ (array, optional) A list of strings\n"
+ " \"support\" (string) client side supported softfork deployment\n"
+ " ,...\n"
+ " ]\n"
" }\n"
"\n"
"\nResult:\n"
"{\n"
- " \"version\" : n, (numeric) The block version\n"
+ " \"version\" : n, (numeric) The preferred block version\n"
" \"rules\" : [ \"rulename\", ... ], (array of strings) specific block rules that are to be enforced\n"
" \"vbavailable\" : { (json object) set of pending, supported versionbit (BIP 9) softfork deployments\n"
- " \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n"
+ " \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n"
" ,...\n"
" },\n"
" \"vbrequired\" : n, (numeric) bit mask of versionbits the server requires set in submissions\n"
- " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
+ " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
" {\n"
- " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n"
- " \"txid\" : \"xxxx\", (string) transaction id encoded in little-endian hexadecimal\n"
- " \"hash\" : \"xxxx\", (string) hash encoded in little-endian hexadecimal (including witness data)\n"
- " \"depends\" : [ (array) array of numbers \n"
- " 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"
+ " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n"
+ " \"txid\" : \"xxxx\", (string) transaction id encoded in little-endian hexadecimal\n"
+ " \"hash\" : \"xxxx\", (string) hash encoded in little-endian hexadecimal (including witness data)\n"
+ " \"depends\" : [ (array) array of numbers \n"
+ " 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"
- " \"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"
- " \"cost\" : n, (numeric) total transaction size cost, 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"
+ " \"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"
" }\n"
" ,...\n"
" ],\n"
- " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
- " \"flags\" : \"flags\" (string) \n"
+ " \"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"
- " \"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"
- " \"mutable\" : [ (array of string) list of ways the block template may be changed \n"
- " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\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"
+ " \"mutable\" : [ (array of string) list of ways the block template may be changed \n"
+ " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n"
" ,...\n"
" ],\n"
- " \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n"
- " \"sigoplimit\" : n, (numeric) cost limit of sigops in blocks\n"
+ " \"noncerange\" : \"00000000ffffffff\",(string) A range of valid nonces\n"
+ " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n"
" \"sizelimit\" : n, (numeric) limit of block size\n"
- " \"costlimit\" : n, (numeric) limit of block cost\n"
+ " \"weightlimit\" : n, (numeric) limit of block weight\n"
" \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
- " \"bits\" : \"xxx\", (string) compressed target of next block\n"
+ " \"bits\" : \"xxxxxxxx\", (string) compressed target of next block\n"
" \"height\" : n (numeric) The height of the next block\n"
"}\n"
@@ -394,9 +396,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
UniValue lpval = NullUniValue;
std::set<std::string> setClientRules;
int64_t nMaxVersionPreVB = -1;
- if (params.size() > 0)
+ if (request.params.size() > 0)
{
- const UniValue& oparam = params[0].get_obj();
+ const UniValue& oparam = request.params[0].get_obj();
const UniValue& modeval = find_value(oparam, "mode");
if (modeval.isStr())
strMode = modeval.get_str();
@@ -456,7 +458,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
if (strMode != "template")
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
- if (vNodes.empty())
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
+ if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0)
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!");
if (IsInitialBlockDownload())
@@ -510,29 +515,35 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
// TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
}
+ const struct BIP9DeploymentInfo& 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 CBlockTemplate* pblocktemplate;
+ 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 = NULL;
+ pindexPrev = nullptr;
// Store the pindexBest used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrevNew = chainActive.Tip();
nStart = GetTime();
+ fLastTemplateSupportsSegwit = fSupportsSegwit;
// Create new block
- if(pblocktemplate)
- {
- delete pblocktemplate;
- pblocktemplate = NULL;
- }
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");
@@ -546,12 +557,16 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
UpdateTime(pblock, consensusParams, pindexPrev);
pblock->nNonce = 0;
+ // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration
+ const bool fPreSegWit = (THRESHOLD_ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache));
+
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;
- BOOST_FOREACH (CTransaction& tx, pblock->vtx) {
+ for (const auto& it : pblock->vtx) {
+ const CTransaction& tx = *it;
uint256 txHash = tx.GetHash();
setTxIndex[txHash] = i++;
@@ -574,8 +589,13 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
int index_in_template = i - 1;
entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template]));
- entry.push_back(Pair("sigops", pblocktemplate->vTxSigOpsCost[index_in_template]));
- entry.push_back(Pair("cost", GetTransactionCost(tx)));
+ int64_t nTxSigOps = pblocktemplate->vTxSigOpsCost[index_in_template];
+ if (fPreSegWit) {
+ assert(nTxSigOps % WITNESS_SCALE_FACTOR == 0);
+ nTxSigOps /= WITNESS_SCALE_FACTOR;
+ }
+ entry.push_back(Pair("sigops", nTxSigOps));
+ entry.push_back(Pair("weight", GetTransactionWeight(tx)));
transactions.push_back(entry);
}
@@ -595,8 +615,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
UniValue aRules(UniValue::VARR);
UniValue vbavailable(UniValue::VOBJ);
- for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) {
- Consensus::DeploymentPos pos = Consensus::DeploymentPos(i);
+ for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
+ Consensus::DeploymentPos pos = Consensus::DeploymentPos(j);
ThresholdState state = VersionBitsState(pindexPrev, consensusParams, pos, versionbitscache);
switch (state) {
case THRESHOLD_DEFINED:
@@ -642,7 +662,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
if (nMaxVersionPreVB >= 2) {
// If VB is supported by the client, nMaxVersionPreVB is -1, so we won't get here
- // Because BIP 34 changed how the generation transaction is serialised, we can only use version/force back to v2 blocks
+ // Because BIP 34 changed how the generation transaction is serialized, we can only use version/force back to v2 blocks
// This is safe to do [otherwise-]unconditionally only because we are throwing an exception above if a non-force deployment gets activated
// Note that this can probably also be removed entirely after the first BIP9 non-force deployment (ie, probably segwit) gets activated
aMutable.push_back("version/force");
@@ -651,19 +671,29 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
result.push_back(Pair("transactions", transactions));
result.push_back(Pair("coinbaseaux", aux));
- result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
+ result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue));
result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)));
result.push_back(Pair("target", hashTarget.GetHex()));
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
result.push_back(Pair("mutable", aMutable));
result.push_back(Pair("noncerange", "00000000ffffffff"));
- result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS_COST));
- result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE));
- result.push_back(Pair("costlimit", (int64_t)MAX_BLOCK_COST));
+ int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST;
+ if (fPreSegWit) {
+ assert(nSigOpLimit % WITNESS_SCALE_FACTOR == 0);
+ nSigOpLimit /= WITNESS_SCALE_FACTOR;
+ }
+ result.push_back(Pair("sigoplimit", nSigOpLimit));
+ if (fPreSegWit) {
+ result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_BASE_SIZE));
+ } else {
+ 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("curtime", pblock->GetBlockTime()));
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
- if (!pblocktemplate->vchCoinbaseCommitment.empty()) {
+
+ if (!pblocktemplate->vchCoinbaseCommitment.empty() && fSupportsSegwit) {
result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end())));
}
@@ -677,29 +707,29 @@ public:
bool found;
CValidationState state;
- submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {};
+ 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 UniValue& params, bool fHelp)
+UniValue submitblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ throw std::runtime_error(
"submitblock \"hexdata\" ( \"jsonparametersobject\" )\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. \"jsonparametersobject\" (string, optional) object of optional parameters\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"
@@ -708,10 +738,17 @@ UniValue submitblock(const UniValue& params, bool fHelp)
+ HelpExampleCli("submitblock", "\"mydata\"")
+ HelpExampleRpc("submitblock", "\"mydata\"")
);
+ }
- CBlock block;
- if (!DecodeHexBlk(block, params[0].get_str()))
+ std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
+ CBlock& block = *blockptr;
+ 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;
@@ -720,10 +757,12 @@ UniValue submitblock(const UniValue& params, bool fHelp)
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;
}
@@ -737,93 +776,66 @@ UniValue submitblock(const UniValue& params, bool fHelp)
}
}
- CValidationState state;
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
- bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL);
+ bool fAccepted = ProcessNewBlock(Params(), blockptr, true, NULL);
UnregisterValidationInterface(&sc);
- if (fBlockPresent)
- {
- if (fAccepted && !sc.found)
+ if (fBlockPresent) {
+ if (fAccepted && !sc.found) {
return "duplicate-inconclusive";
+ }
return "duplicate";
}
- if (fAccepted)
- {
- if (!sc.found)
- return "inconclusive";
- state = sc.state;
+ if (!sc.found) {
+ return "inconclusive";
}
- return BIP22ValidationResult(state);
+ return BIP22ValidationResult(sc.state);
}
-UniValue estimatefee(const UniValue& params, bool fHelp)
+UniValue estimatefee(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
"estimatefee nblocks\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
- "confirmation within nblocks blocks.\n"
+ "confirmation within nblocks blocks. Uses virtual transaction size of transaction\n"
+ "as defined in BIP 141 (witness data is discounted).\n"
"\nArguments:\n"
- "1. nblocks (numeric)\n"
+ "1. nblocks (numeric, required)\n"
"\nResult:\n"
"n (numeric) estimated fee-per-kilobyte\n"
"\n"
"A negative value is returned if not enough transactions and blocks\n"
"have been observed to make an estimate.\n"
+ "-1 is always returned for nblocks == 1 as it is impossible to calculate\n"
+ "a fee that is high enough to get reliably included in the next block.\n"
"\nExample:\n"
+ HelpExampleCli("estimatefee", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
- int nBlocks = params[0].get_int();
+ 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 UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "estimatepriority nblocks\n"
- "\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
- "confirmation within nblocks blocks.\n"
- "\nArguments:\n"
- "1. nblocks (numeric)\n"
- "\nResult:\n"
- "n (numeric) estimated priority\n"
- "\n"
- "A negative value is returned if not enough transactions and blocks\n"
- "have been observed to make an estimate.\n"
- "\nExample:\n"
- + HelpExampleCli("estimatepriority", "6")
- );
-
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
-
- int nBlocks = params[0].get_int();
- if (nBlocks < 1)
- nBlocks = 1;
-
- return mempool.estimatePriority(nBlocks);
-}
-
-UniValue estimatesmartfee(const UniValue& params, bool fHelp)
+UniValue estimatesmartfee(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
"estimatesmartfee nblocks\n"
"\nWARNING: This interface is unstable and may disappear or change!\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"
- "for which the estimate is valid.\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"
"\nResult:\n"
@@ -839,74 +851,36 @@ UniValue estimatesmartfee(const UniValue& params, bool fHelp)
+ HelpExampleCli("estimatesmartfee", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
- int nBlocks = params[0].get_int();
+ int nBlocks = request.params[0].get_int();
UniValue result(UniValue::VOBJ);
int answerFound;
- CFeeRate feeRate = mempool.estimateSmartFee(nBlocks, &answerFound);
+ CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &answerFound, ::mempool);
result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
result.push_back(Pair("blocks", answerFound));
return result;
}
-UniValue estimatesmartpriority(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "estimatesmartpriority nblocks\n"
- "\nWARNING: 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"
- "\nArguments:\n"
- "1. nblocks (numeric)\n"
- "\nResult:\n"
- "{\n"
- " \"priority\" : x.x, (numeric) estimated priority\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"
- "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"
- "\nExample:\n"
- + HelpExampleCli("estimatesmartpriority", "6")
- );
-
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
-
- int nBlocks = params[0].get_int();
-
- UniValue result(UniValue::VOBJ);
- int answerFound;
- double priority = mempool.estimateSmartPriority(nBlocks, &answerFound);
- result.push_back(Pair("priority", priority));
- result.push_back(Pair("blocks", answerFound));
- return result;
-}
-
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
- { "mining", "getnetworkhashps", &getnetworkhashps, true },
- { "mining", "getmininginfo", &getmininginfo, true },
- { "mining", "prioritisetransaction", &prioritisetransaction, true },
- { "mining", "getblocktemplate", &getblocktemplate, true },
- { "mining", "submitblock", &submitblock, true },
-
- { "generating", "generate", &generate, true },
- { "generating", "generatetoaddress", &generatetoaddress, true },
-
- { "util", "estimatefee", &estimatefee, true },
- { "util", "estimatepriority", &estimatepriority, true },
- { "util", "estimatesmartfee", &estimatesmartfee, true },
- { "util", "estimatesmartpriority", &estimatesmartpriority, true },
+ { "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} },
+ { "mining", "getmininginfo", &getmininginfo, true, {} },
+ { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","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", "estimatesmartfee", &estimatesmartfee, true, {"nblocks"} },
};
-void RegisterMiningRPCCommands(CRPCTable &tableRPC)
+void RegisterMiningRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index a8c5bcd177..1f973a0c18 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -1,31 +1,36 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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 "base58.h"
+#include "chain.h"
#include "clientversion.h"
#include "init.h"
-#include "main.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 <stdint.h>
+#ifdef HAVE_MALLOC_INFO
+#include <malloc.h>
+#endif
#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
@@ -39,12 +44,12 @@ using namespace std;
*
* Or alternatively, create a specific query method for the information.
**/
-UniValue getinfo(const UniValue& params, bool fHelp)
+UniValue getinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"getinfo\n"
- "Returns an object containing various state info.\n"
+ "\nDEPRECATED. Returns an object containing various state info.\n"
"\nResult:\n"
"{\n"
" \"version\": xxxxx, (numeric) the server version\n"
@@ -57,11 +62,11 @@ UniValue getinfo(const UniValue& params, bool fHelp)
" \"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 GMT epoch) of the oldest pre-generated key in the key pool\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"
+ " \"relayfee\": x.xxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": \"...\" (string) any error messages\n"
"}\n"
"\nExamples:\n"
@@ -70,7 +75,9 @@ UniValue getinfo(const UniValue& params, bool fHelp)
);
#ifdef ENABLE_WALLET
- LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+
+ LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
@@ -82,24 +89,26 @@ UniValue getinfo(const UniValue& params, bool fHelp)
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())));
+ if (pwallet) {
+ obj.push_back(Pair("walletversion", pwallet->GetVersion()));
+ obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance())));
}
#endif
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
- obj.push_back(Pair("connections", (int)vNodes.size()));
- obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
+ 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() : std::string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
+ 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 (pwallet) {
+ obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime()));
+ obj.push_back(Pair("keypoolsize", (int)pwallet->GetKeyPoolSize()));
+ }
+ if (pwallet && pwallet->IsCrypted()) {
+ obj.push_back(Pair("unlocked_until", pwallet->nRelockTime));
}
- 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())));
@@ -111,13 +120,17 @@ UniValue getinfo(const UniValue& params, bool fHelp)
class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
public:
+ CWallet * const pwallet;
+
+ 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)) {
+ if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
}
@@ -128,7 +141,7 @@ public:
UniValue obj(UniValue::VOBJ);
CScript subscript;
obj.push_back(Pair("isscript", true));
- if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) {
+ if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
std::vector<CTxDestination> addresses;
txnouttype whichType;
int nRequired;
@@ -147,18 +160,18 @@ public:
};
#endif
-UniValue validateaddress(const UniValue& params, bool fHelp)
+UniValue validateaddress(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "validateaddress \"bitcoinaddress\"\n"
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
+ "validateaddress \"address\"\n"
"\nReturn information about the given bitcoin address.\n"
"\nArguments:\n"
- "1. \"bitcoinaddress\" (string, required) The bitcoin address to validate\n"
+ "1. \"address\" (string, required) The bitcoin address to validate\n"
"\nResult:\n"
"{\n"
" \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
- " \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n"
+ " \"address\" : \"address\", (string) The bitcoin address validated\n"
" \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
" \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
@@ -166,6 +179,7 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
" \"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"
@@ -175,12 +189,14 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
);
#ifdef ENABLE_WALLET
- LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+
+ LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
bool isValid = address.IsValid();
UniValue ret(UniValue::VOBJ);
@@ -188,48 +204,61 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
if (isValid)
{
CTxDestination dest = address.Get();
- string currentAddress = address.ToString();
+ std::string currentAddress = address.ToString();
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;
+ isminetype mine = pwallet ? IsMine(*pwallet, 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);
+ 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));
+ if (pwallet && pwallet->mapAddressBook.count(dest)) {
+ ret.push_back(Pair("account", pwallet->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) {
+ const auto& meta = pwallet->mapKeyMetadata;
+ auto it = address.GetKeyID(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,18 +267,18 @@ CScript _createmultisig_redeemScript(const UniValue& params)
#ifdef ENABLE_WALLET
// Case 1: Bitcoin address and we have full public key:
CBitcoinAddress address(ks);
- if (pwalletMain && address.IsValid())
- {
+ if (pwallet && address.IsValid()) {
CKeyID keyID;
if (!address.GetKeyID(keyID))
- throw runtime_error(
+ throw std::runtime_error(
strprintf("%s does not refer to a key",ks));
CPubKey vchPubKey;
- if (!pwalletMain->GetPubKey(keyID, vchPubKey))
- throw runtime_error(
+ 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;
}
@@ -260,28 +289,34 @@ 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;
}
-UniValue createmultisig(const UniValue& params, bool fHelp)
+UniValue createmultisig(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 2)
+#ifdef ENABLE_WALLET
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+#else
+ CWallet * const pwallet = NULL;
+#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"
@@ -305,11 +340,11 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
"\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(params);
+ CScript inner = _createmultisig_redeemScript(pwallet, request.params);
CScriptID innerID(inner);
CBitcoinAddress address(innerID);
@@ -320,51 +355,14 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
return result;
}
-UniValue createwitnessaddress(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() < 1 || params.size() > 1)
- {
- string msg = "createwitnessaddress \"script\"\n"
- "\nCreates a witness address for a particular script.\n"
- "It returns a json object with the address and witness script.\n"
-
- "\nArguments:\n"
- "1. \"script\" (string, required) A hex encoded script\n"
-
- "\nResult:\n"
- "{\n"
- " \"address\":\"multisigaddress\", (string) The value of the new address (P2SH of witness script).\n"
- " \"witnessScript\":\"script\" (string) The string value of the hex-encoded witness script.\n"
- "}\n"
- ;
- throw runtime_error(msg);
- }
-
- if (!IsHex(params[0].get_str())) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Script must be hex-encoded");
- }
-
- std::vector<unsigned char> code = ParseHex(params[0].get_str());
- CScript script(code.begin(), code.end());
- CScript witscript = GetScriptForWitness(script);
- CScriptID witscriptid(witscript);
- CBitcoinAddress address(witscriptid);
-
- UniValue result(UniValue::VOBJ);
- result.push_back(Pair("address", address.ToString()));
- result.push_back(Pair("witnessScript", HexStr(witscript.begin(), witscript.end())));
-
- return result;
-}
-
-UniValue verifymessage(const UniValue& params, bool fHelp)
+UniValue verifymessage(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 3)
- throw runtime_error(
- "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
+ if (request.fHelp || request.params.size() != 3)
+ throw std::runtime_error(
+ "verifymessage \"address\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
"\nArguments:\n"
- "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the signature.\n"
+ "1. \"address\" (string, required) The bitcoin address to use for the signature.\n"
"2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
"3. \"message\" (string, required) The message that was signed.\n"
"\nResult:\n"
@@ -373,18 +371,18 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
"\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 = params[0].get_str();
- string strSign = params[1].get_str();
- string strMessage = 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())
@@ -395,7 +393,7 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
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");
@@ -411,10 +409,10 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
return (pubkey.GetID() == keyID);
}
-UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
+UniValue signmessagewithprivkey(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 2)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 2)
+ throw std::runtime_error(
"signmessagewithprivkey \"privkey\" \"message\"\n"
"\nSign a message with the private key of an address\n"
"\nArguments:\n"
@@ -426,13 +424,13 @@ UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
"\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 = params[0].get_str();
- string strMessage = 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);
@@ -446,17 +444,17 @@ UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
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());
}
-UniValue setmocktime(const UniValue& params, bool fHelp)
+UniValue setmocktime(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
"setmocktime timestamp\n"
"\nSet the local time to given timestamp (-regtest only)\n"
"\nArguments:\n"
@@ -465,41 +463,199 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
);
if (!Params().MineBlocksOnDemand())
- throw runtime_error("setmocktime for regression testing (-regtest mode) only");
+ throw std::runtime_error("setmocktime for regression testing (-regtest mode) only");
+
+ // 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);
- // cs_vNodes is locked and node send/receive times are updated
- // atomically with the time change to prevent peers from being
- // disconnected because we think we haven't communicated with them
- // in a long time.
- LOCK2(cs_main, cs_vNodes);
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
+ SetMockTime(request.params[0].get_int64());
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
- SetMockTime(params[0].get_int64());
+ return NullUniValue;
+}
+
+static UniValue RPCLockedMemoryInfo()
+{
+ LockedPool::Stats stats = LockedPoolManager::Instance().stats();
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("used", uint64_t(stats.used)));
+ obj.push_back(Pair("free", uint64_t(stats.free)));
+ obj.push_back(Pair("total", uint64_t(stats.total)));
+ obj.push_back(Pair("locked", uint64_t(stats.locked)));
+ obj.push_back(Pair("chunks_used", uint64_t(stats.chunks_used)));
+ obj.push_back(Pair("chunks_free", uint64_t(stats.chunks_free)));
+ return obj;
+}
- uint64_t t = GetTime();
- BOOST_FOREACH(CNode* pnode, vNodes) {
- pnode->nLastSend = pnode->nLastRecv = t;
+#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
- return NullUniValue;
+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() > 1)
+ throw std::runtime_error(
+ "getmemoryinfo (\"mode\")\n"
+ "Returns an object containing information about memory usage.\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"
+ " \"free\": xxxxx, (numeric) Number of bytes available in current arenas\n"
+ " \"total\": xxxxxxx, (numeric) Total number of bytes managed\n"
+ " \"locked\": xxxxxx, (numeric) Amount of bytes that succeeded locking. If this number is smaller than total, locking pages failed at some point and key data could be swapped to disk.\n"
+ " \"chunks_used\": xxxxx, (numeric) Number allocated chunks\n"
+ " \"chunks_free\": xxxxx, (numeric) Number unused chunks\n"
+ " }\n"
+ "}\n"
+ "\nResult (mode \"mallocinfo\"):\n"
+ "\"<malloc version=\"1\">...\"\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getmemoryinfo", "")
+ + HelpExampleRpc("getmemoryinfo", "")
+ );
+
+ std::string mode = (request.params.size() < 1 || 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.size() > 0 && request.params[0].isArray()) {
+ logCategories |= getCategoryMask(request.params[0]);
+ }
+
+ if (request.params.size() > 1 && 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 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"
+ "bitcoin-cli and the GUI. There is no server-side difference."
+ );
+
+ return request.params;
}
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
- { "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */
- { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */
- { "util", "createmultisig", &createmultisig, true },
- { "util", "createwitnessaddress", &createwitnessaddress, true },
- { "util", "verifymessage", &verifymessage, true },
- { "util", "signmessagewithprivkey", &signmessagewithprivkey, true },
+ { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */
+ { "control", "getmemoryinfo", &getmemoryinfo, true, {"mode"} },
+ { "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"} },
/* Not shown in help */
- { "hidden", "setmocktime", &setmocktime, true },
+ { "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", "logging", &logging, true, {"include", "exclude"}},
};
-void RegisterMiscRPCCommands(CRPCTable &tableRPC)
+void RegisterMiscRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index b85c7b2e1a..cde5ae723b 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -6,9 +6,11 @@
#include "chainparams.h"
#include "clientversion.h"
-#include "main.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"
@@ -21,12 +23,10 @@
#include <univalue.h>
-using namespace std;
-
-UniValue getconnectioncount(const UniValue& params, bool fHelp)
+UniValue getconnectioncount(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"getconnectioncount\n"
"\nReturns the number of connections to other nodes.\n"
"\nResult:\n"
@@ -36,15 +36,16 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getconnectioncount", "")
);
- LOCK2(cs_main, cs_vNodes);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- return (int)vNodes.size();
+ return (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL);
}
-UniValue ping(const UniValue& params, bool fHelp)
+UniValue ping(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ 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"
@@ -54,33 +55,20 @@ UniValue ping(const UniValue& params, bool fHelp)
+ HelpExampleRpc("ping", "")
);
- // Request that each node send a ping during next message processing pass
- LOCK2(cs_main, cs_vNodes);
-
- BOOST_FOREACH(CNode* pNode, vNodes) {
- pNode->fPingQueued = true;
- }
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ // Request that each node send a ping during next message processing pass
+ g_connman->ForEachNode([](CNode* pnode) {
+ pnode->fPingQueued = true;
+ });
return NullUniValue;
}
-static void CopyNodeStats(std::vector<CNodeStats>& vstats)
-{
- vstats.clear();
-
- LOCK(cs_vNodes);
- vstats.reserve(vNodes.size());
- BOOST_FOREACH(CNode* pnode, vNodes) {
- CNodeStats stats;
- pnode->copyStats(stats);
- vstats.push_back(stats);
- }
-}
-
-UniValue getpeerinfo(const UniValue& params, bool fHelp)
+UniValue getpeerinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"getpeerinfo\n"
"\nReturns data about each connected network node as a json array of objects.\n"
"\nResult:\n"
@@ -103,6 +91,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
" \"version\": v, (numeric) The peer version, such as 7001\n"
" \"subver\": \"/Satoshi:0.8.5/\", (string) The string version\n"
" \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
+ " \"addnode\": true|false, (boolean) Whether connection was due to addnode and is using an addnode slot\n"
" \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
" \"banscore\": n, (numeric) The ban score\n"
" \"synced_headers\": n, (numeric) The last header we have in common with this peer\n"
@@ -110,13 +99,14 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
" \"inflight\": [\n"
" n, (numeric) The heights of blocks we're currently asking from this peer\n"
" ...\n"
- " ]\n"
+ " ],\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"
+ " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
" ...\n"
- " }\n"
+ " },\n"
" \"bytesrecv_per_msg\": {\n"
- " \"addr\": n, (numeric) The total bytes received aggregated by message type\n"
+ " \"addr\": n, (numeric) The total bytes received aggregated by message type\n"
" ...\n"
" }\n"
" }\n"
@@ -127,10 +117,11 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getpeerinfo", "")
);
- LOCK(cs_main);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- vector<CNodeStats> vstats;
- CopyNodeStats(vstats);
+ std::vector<CNodeStats> vstats;
+ g_connman->GetNodeStats(vstats);
UniValue ret(UniValue::VARR);
@@ -152,16 +143,17 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("timeoffset", stats.nTimeOffset));
if (stats.dPingTime > 0.0)
obj.push_back(Pair("pingtime", stats.dPingTime));
- if (stats.dPingMin < std::numeric_limits<int64_t>::max()/1e6)
- obj.push_back(Pair("minping", stats.dPingMin));
+ if (stats.dMinPing < 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));
+ obj.push_back(Pair("addnode", stats.fAddnode));
obj.push_back(Pair("startingheight", stats.nStartingHeight));
if (fStateStats) {
obj.push_back(Pair("banscore", statestats.nMisbehavior));
@@ -195,14 +187,14 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
return ret;
}
-UniValue addnode(const UniValue& params, bool fHelp)
+UniValue addnode(const JSONRPCRequest& request)
{
- string strCommand;
- if (params.size() == 2)
- strCommand = params[1].get_str();
- if (fHelp || params.size() != 2 ||
+ std::string strCommand;
+ if (request.params.size() == 2)
+ 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"
"Or try a connection to a node once.\n"
@@ -214,69 +206,84 @@ UniValue addnode(const UniValue& params, bool fHelp)
+ HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")
);
- string strNode = params[0].get_str();
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
+ std::string strNode = request.params[0].get_str();
if (strCommand == "onetry")
{
CAddress addr;
- OpenNetworkConnection(addr, false, NULL, strNode.c_str());
+ g_connman->OpenNetworkConnection(addr, false, NULL, strNode.c_str());
return NullUniValue;
}
- LOCK(cs_vAddedNodes);
- vector<string>::iterator it = vAddedNodes.begin();
- for(; it != vAddedNodes.end(); it++)
- if (strNode == *it)
- break;
-
if (strCommand == "add")
{
- if (it != vAddedNodes.end())
+ if(!g_connman->AddNode(strNode))
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
- vAddedNodes.push_back(strNode);
}
else if(strCommand == "remove")
{
- if (it == vAddedNodes.end())
+ if(!g_connman->RemoveAddedNode(strNode))
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
- vAddedNodes.erase(it);
}
return NullUniValue;
}
-UniValue disconnectnode(const UniValue& params, bool fHelp)
+UniValue disconnectnode(const JSONRPCRequest& request)
{
- if (fHelp || 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")
);
- CNode* pNode = FindNode(params[0].get_str());
- if (pNode == NULL)
- throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
+ bool success;
+ const UniValue &address_arg = request.params[0];
+ const UniValue &id_arg = request.params.size() < 2 ? NullUniValue : 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.");
+ }
- pNode->fDisconnect = true;
+ if (!success) {
+ throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
+ }
return NullUniValue;
}
-UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
+UniValue getaddednodeinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
- "getaddednodeinfo dummy ( \"node\" )\n"
+ if (request.fHelp || request.params.size() > 1)
+ 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"
"\nArguments:\n"
- "1. dummy (boolean, required) Kept for historical purposes but ignored\n"
- "2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
+ "1. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
"\nResult:\n"
"[\n"
" {\n"
@@ -297,12 +304,15 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"")
);
- std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
+ std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
- if (params.size() == 2) {
+ if (request.params.size() == 1) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
- if (info.strAddedNode == params[1].get_str()) {
+ if (info.strAddedNode == request.params[0].get_str()) {
vInfo.assign(1, info);
found = true;
break;
@@ -333,10 +343,10 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
return ret;
}
-UniValue getnettotals(const UniValue& params, bool fHelp)
+UniValue getnettotals(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() > 0)
+ throw std::runtime_error(
"getnettotals\n"
"\nReturns information about network traffic, including bytes in, bytes out,\n"
"and current time.\n"
@@ -344,7 +354,7 @@ UniValue getnettotals(const UniValue& params, bool fHelp)
"{\n"
" \"totalbytesrecv\": n, (numeric) Total bytes received\n"
" \"totalbytessent\": n, (numeric) Total bytes sent\n"
- " \"timemillis\": t, (numeric) Total cpu time\n"
+ " \"timemillis\": t, (numeric) Current UNIX time in milliseconds\n"
" \"uploadtarget\":\n"
" {\n"
" \"timeframe\": n, (numeric) Length of the measuring timeframe in seconds\n"
@@ -359,19 +369,21 @@ UniValue getnettotals(const UniValue& params, bool fHelp)
+ HelpExampleCli("getnettotals", "")
+ HelpExampleRpc("getnettotals", "")
);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv()));
- obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent()));
+ obj.push_back(Pair("totalbytesrecv", g_connman->GetTotalBytesRecv()));
+ obj.push_back(Pair("totalbytessent", g_connman->GetTotalBytesSent()));
obj.push_back(Pair("timemillis", GetTimeMillis()));
UniValue outboundLimit(UniValue::VOBJ);
- outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe()));
- outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget()));
- outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false)));
- outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true)));
- outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft()));
- outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle()));
+ outboundLimit.push_back(Pair("timeframe", g_connman->GetMaxOutboundTimeframe()));
+ outboundLimit.push_back(Pair("target", g_connman->GetMaxOutboundTarget()));
+ outboundLimit.push_back(Pair("target_reached", g_connman->OutboundTargetReached(false)));
+ outboundLimit.push_back(Pair("serve_historical_blocks", !g_connman->OutboundTargetReached(true)));
+ outboundLimit.push_back(Pair("bytes_left_in_cycle", g_connman->GetOutboundTargetBytesLeft()));
+ outboundLimit.push_back(Pair("time_left_in_cycle", g_connman->GetMaxOutboundTimeLeftInCycle()));
obj.push_back(Pair("uploadtarget", outboundLimit));
return obj;
}
@@ -390,17 +402,17 @@ 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);
}
return networks;
}
-UniValue getnetworkinfo(const UniValue& params, bool fHelp)
+UniValue getnetworkinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"getnetworkinfo\n"
"Returns an object containing various state info regarding P2P networking.\n"
"\nResult:\n"
@@ -412,16 +424,19 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
" \"localrelay\": true|false, (bool) true if transaction relay is requested from peers\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
+ " \"networkactive\": true|false, (bool) whether p2p networking is enabled\n"
" \"networks\": [ (array) information per network\n"
" {\n"
" \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n"
" \"limited\": true|false, (boolean) is the network limited using -onlynet?\n"
" \"reachable\": true|false, (boolean) is the network reachable?\n"
" \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n"
+ " \"proxy_randomize_credentials\": true|false, (string) Whether randomized credentials are used\n"
" }\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"
@@ -430,7 +445,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
" }\n"
" ,...\n"
" ]\n"
- " \"warnings\": \"...\" (string) any network warnings (such as alert messages) \n"
+ " \"warnings\": \"...\" (string) any network warnings\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getnetworkinfo", "")
@@ -438,17 +453,21 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
-
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion", strSubVersion));
obj.push_back(Pair("protocolversion",PROTOCOL_VERSION));
- obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
+ if(g_connman)
+ obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices())));
obj.push_back(Pair("localrelay", fRelayTxes));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
- obj.push_back(Pair("connections", (int)vNodes.size()));
+ if (g_connman) {
+ obj.push_back(Pair("networkactive", g_connman->GetNetworkActive()));
+ obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
+ }
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);
@@ -466,69 +485,74 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
return obj;
}
-UniValue setban(const UniValue& params, bool fHelp)
+UniValue setban(const JSONRPCRequest& request)
{
- string strCommand;
- if (params.size() >= 2)
- strCommand = params[1].get_str();
- if (fHelp || params.size() < 2 ||
+ std::string strCommand;
+ if (request.params.size() >= 2)
+ strCommand = request.params[1].get_str();
+ if (request.fHelp || request.params.size() < 2 ||
(strCommand != "add" && strCommand != "remove"))
- throw runtime_error(
- "setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n"
+ throw std::runtime_error(
+ "setban \"subnet\" \"add|remove\" (bantime) (absolute)\n"
"\nAttempts add or remove a IP/Subnet from the banned list.\n"
"\nArguments:\n"
- "1. \"ip(/netmask)\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n"
+ "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"
"\nExamples:\n"
+ HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
- + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\" 86400")
+ + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
CSubNet subNet;
CNetAddr netAddr;
bool isSubnet = false;
- if (params[0].get_str().find("/") != string::npos)
+ if (request.params[0].get_str().find("/") != std::string::npos)
isSubnet = true;
- if (!isSubnet)
- netAddr = CNetAddr(params[0].get_str());
+ if (!isSubnet) {
+ CNetAddr resolved;
+ LookupHost(request.params[0].get_str().c_str(), resolved, false);
+ netAddr = resolved;
+ }
else
- subNet = CSubNet(params[0].get_str());
+ 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")
{
- if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr))
+ if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr))
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
int64_t banTime = 0; //use standard bantime if not specified
- if (params.size() >= 3 && !params[2].isNull())
- banTime = params[2].get_int64();
+ if (request.params.size() >= 3 && !request.params[2].isNull())
+ banTime = request.params[2].get_int64();
bool absolute = false;
- if (params.size() == 4 && params[3].isTrue())
+ if (request.params.size() == 4 && request.params[3].isTrue())
absolute = true;
- isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
+ isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
}
else if(strCommand == "remove")
{
- if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) ))
- throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
+ if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))
+ throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned.");
}
return NullUniValue;
}
-UniValue listbanned(const UniValue& params, bool fHelp)
+UniValue listbanned(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"listbanned\n"
"\nList all banned IPs/Subnets.\n"
"\nExamples:\n"
@@ -536,8 +560,11 @@ UniValue listbanned(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listbanned", "")
);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
banmap_t banMap;
- CNode::GetBanned(banMap);
+ g_connman->GetBanned(banMap);
UniValue bannedAddresses(UniValue::VARR);
for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
@@ -555,40 +582,63 @@ UniValue listbanned(const UniValue& params, bool fHelp)
return bannedAddresses;
}
-UniValue clearbanned(const UniValue& params, bool fHelp)
+UniValue clearbanned(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"clearbanned\n"
"\nClear all banned IPs.\n"
"\nExamples:\n"
+ HelpExampleCli("clearbanned", "")
+ HelpExampleRpc("clearbanned", "")
);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- CNode::ClearBanned();
+ g_connman->ClearBanned();
return NullUniValue;
}
+UniValue setnetworkactive(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 1) {
+ throw std::runtime_error(
+ "setnetworkactive true|false\n"
+ "\nDisable/enable all p2p network activity.\n"
+ "\nArguments:\n"
+ "1. \"state\" (boolean, required) true to enable networking, false to disable\n"
+ );
+ }
+
+ if (!g_connman) {
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ }
+
+ g_connman->SetNetworkActive(request.params[0].get_bool());
+
+ return g_connman->GetNetworkActive();
+}
+
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
- { "network", "getconnectioncount", &getconnectioncount, true },
- { "network", "ping", &ping, true },
- { "network", "getpeerinfo", &getpeerinfo, true },
- { "network", "addnode", &addnode, true },
- { "network", "disconnectnode", &disconnectnode, true },
- { "network", "getaddednodeinfo", &getaddednodeinfo, true },
- { "network", "getnettotals", &getnettotals, true },
- { "network", "getnetworkinfo", &getnetworkinfo, true },
- { "network", "setban", &setban, true },
- { "network", "listbanned", &listbanned, true },
- { "network", "clearbanned", &clearbanned, true },
+ { "network", "getconnectioncount", &getconnectioncount, true, {} },
+ { "network", "ping", &ping, true, {} },
+ { "network", "getpeerinfo", &getpeerinfo, true, {} },
+ { "network", "addnode", &addnode, true, {"node","command"} },
+ { "network", "disconnectnode", &disconnectnode, true, {"address", "nodeid"} },
+ { "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"} },
};
-void RegisterNetRPCCommands(CRPCTable &tableRPC)
+void RegisterNetRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index f5275062a2..823a5775f6 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -15,8 +15,6 @@
#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
@@ -26,13 +24,13 @@ using namespace std;
* 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
*/
-string JSONRPCRequest(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));
request.push_back(Pair("params", params));
request.push_back(Pair("id", id));
- return request.write() + "\n";
+ return request;
}
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
@@ -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,24 +66,25 @@ static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";
-boost::filesystem::path GetAuthCookieFile()
+fs::path GetAuthCookieFile()
{
- boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
+ fs::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
if (!path.is_complete()) path = GetDataDir() / path;
return path;
}
bool GenerateAuthCookie(std::string *cookie_out)
{
- unsigned char rand_pwd[32];
- GetRandBytes(rand_pwd, 32);
- std::string cookie = COOKIEAUTH_USER + ":" + EncodeBase64(&rand_pwd[0],32);
+ const size_t COOKIE_SIZE = 32;
+ unsigned char rand_pwd[COOKIE_SIZE];
+ GetRandBytes(rand_pwd, COOKIE_SIZE);
+ std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd, rand_pwd+COOKIE_SIZE);
/** the umask determines what permissions are used to create this file -
* these are set to 077 in init.cpp unless overridden with -sysperms.
*/
std::ofstream file;
- boost::filesystem::path filepath = GetAuthCookieFile();
+ fs::path filepath = GetAuthCookieFile();
file.open(filepath.string().c_str());
if (!file.is_open()) {
LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
@@ -104,7 +103,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;
@@ -119,8 +118,8 @@ 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());
}
}
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 55d0aac68b..70f7092cfe 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -1,16 +1,17 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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_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,25 +32,31 @@ 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,
//! General application defined errors
- RPC_MISC_ERROR = -1, //! std::exception thrown in command handling
- RPC_FORBIDDEN_BY_SAFE_MODE = -2, //! Server is in safe mode, and command is not allowed in safe mode
- RPC_TYPE_ERROR = -3, //! Unexpected type was passed as parameter
- RPC_INVALID_ADDRESS_OR_KEY = -5, //! Invalid address or key
- RPC_OUT_OF_MEMORY = -7, //! Ran out of memory during operation
- RPC_INVALID_PARAMETER = -8, //! Invalid, missing or duplicate parameter
- RPC_DATABASE_ERROR = -20, //! Database error
- RPC_DESERIALIZATION_ERROR = -22, //! Error parsing or validating structure in raw format
- RPC_VERIFY_ERROR = -25, //! General error during transaction or block submission
- 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_MISC_ERROR = -1, //!< std::exception thrown in command handling
+ RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode
+ RPC_TYPE_ERROR = -3, //!< Unexpected type was passed as parameter
+ RPC_INVALID_ADDRESS_OR_KEY = -5, //!< Invalid address or key
+ RPC_OUT_OF_MEMORY = -7, //!< Ran out of memory during operation
+ RPC_INVALID_PARAMETER = -8, //!< Invalid, missing or duplicate parameter
+ RPC_DATABASE_ERROR = -20, //!< Database error
+ RPC_DESERIALIZATION_ERROR = -22, //!< Error parsing or validating structure in raw format
+ RPC_VERIFY_ERROR = -25, //!< General error during transaction or block submission
+ 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
//! Aliases for backward compatibility
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
@@ -57,32 +64,33 @@ enum RPCErrorCode
RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN,
//! P2P client errors
- RPC_CLIENT_NOT_CONNECTED = -9, //! Bitcoin is not connected
- RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks
- RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added
- RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before
- RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes
- RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet
+ RPC_CLIENT_NOT_CONNECTED = -9, //!< Bitcoin is not connected
+ RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //!< Still downloading initial blocks
+ RPC_CLIENT_NODE_ALREADY_ADDED = -23, //!< Node is already added
+ RPC_CLIENT_NODE_NOT_ADDED = -24, //!< Node has not been added before
+ RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes
+ RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
+ RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found
//! Wallet errors
- RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.)
- RPC_WALLET_INSUFFICIENT_FUNDS = -6, //! Not enough funds in wallet or account
- RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //! Invalid account name
- RPC_WALLET_KEYPOOL_RAN_OUT = -12, //! Keypool ran out, call keypoolrefill first
- RPC_WALLET_UNLOCK_NEEDED = -13, //! Enter the wallet passphrase with walletpassphrase first
- RPC_WALLET_PASSPHRASE_INCORRECT = -14, //! The wallet passphrase entered was incorrect
- 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_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.)
+ RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account
+ RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //!< Invalid account name
+ RPC_WALLET_KEYPOOL_RAN_OUT = -12, //!< Keypool ran out, call keypoolrefill first
+ RPC_WALLET_UNLOCK_NEEDED = -13, //!< Enter the wallet passphrase with walletpassphrase first
+ RPC_WALLET_PASSPHRASE_INCORRECT = -14, //!< The wallet passphrase entered was incorrect
+ 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
};
-std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id);
+UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id);
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
UniValue JSONRPCError(int code, const std::string& message);
/** Get name of RPC authentication cookie file */
-boost::filesystem::path GetAuthCookieFile();
+fs::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 */
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 3270cd384f..3947fb3f7d 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -10,7 +10,7 @@
#include "core_io.h"
#include "init.h"
#include "keystore.h"
-#include "main.h"
+#include "validation.h"
#include "merkleblock.h"
#include "net.h"
#include "policy/policy.h"
@@ -24,6 +24,7 @@
#include "uint256.h"
#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
+#include "wallet/rpcwallet.h"
#include "wallet/wallet.h"
#endif
@@ -33,82 +34,15 @@
#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.wit.IsNull()) {
- if (!tx.wit.vtxinwit[i].IsNull()) {
- UniValue txinwitness(UniValue::VARR);
- for (unsigned int j = 0; j < tx.wit.vtxinwit[i].scriptWitness.stack.size(); j++) {
- std::vector<unsigned char> item = tx.wit.vtxinwit[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);
if (!hashBlock.IsNull()) {
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
@@ -126,26 +60,28 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
}
}
-UniValue getrawtransaction(const UniValue& params, bool fHelp)
+UniValue getrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ throw std::runtime_error(
"getrawtransaction \"txid\" ( verbose )\n"
- "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n"
- "or there is an 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.\n"
+
+ "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n"
+ "enabled, it also works for blockchain transactions.\n"
+ "DEPRECATED: for now, it also works for transactions with unspent outputs.\n"
+
"\nReturn the raw transaction data.\n"
- "\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n"
- "If verbose is non-zero, returns an Object with information about 'txid'.\n"
+ "\nIf verbose is 'true', returns an Object with information about 'txid'.\n"
+ "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
- "2. verbose (numeric, optional, default=0) If 0, 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 0):\n"
+ "\nResult (if verbose is not set or set to false):\n"
"\"data\" (string) The serialized, hex-encoded data for 'txid'\n"
- "\nResult (if verbose > 0):\n"
+ "\nResult (if verbose is set to true):\n"
"{\n"
" \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n"
" \"txid\" : \"id\", (string) The transaction id (same as provided)\n"
@@ -177,7 +113,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
" \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
- " \"bitcoinaddress\" (string) bitcoin address\n"
+ " \"address\" (string) bitcoin address\n"
" ,...\n"
" ]\n"
" }\n"
@@ -192,66 +128,81 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
"\nExamples:\n"
+ HelpExampleCli("getrawtransaction", "\"mytxid\"")
- + HelpExampleCli("getrawtransaction", "\"mytxid\" 1")
- + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
+ + HelpExampleCli("getrawtransaction", "\"mytxid\" true")
+ + HelpExampleRpc("getrawtransaction", "\"mytxid\", true")
);
LOCK(cs_main);
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
+ // Accept either a bool (true) or a num (>=1) to indicate verbose output.
bool fVerbose = false;
- if (params.size() > 1)
- fVerbose = (params[1].get_int() != 0);
+ if (request.params.size() > 1) {
+ if (request.params[1].isNum()) {
+ if (request.params[1].get_int() != 0) {
+ fVerbose = true;
+ }
+ }
+ else if(request.params[1].isBool()) {
+ if(request.params[1].isTrue()) {
+ fVerbose = true;
+ }
+ }
+ else {
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid type provided. Verbose parameter must be a boolean.");
+ }
+ }
- CTransaction tx;
+ CTransactionRef tx;
uint256 hashBlock;
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string(fTxIndex ? "No such mempool or blockchain transaction"
+ : "No such mempool transaction. Use -txindex to enable blockchain transaction queries") +
+ ". Use gettransaction for wallet transactions.");
- string strHex = EncodeHexTx(tx);
+ std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags());
if (!fVerbose)
return strHex;
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", strHex));
- TxToJSON(tx, hashBlock, result);
+ TxToJSON(*tx, hashBlock, result);
return result;
}
-UniValue gettxoutproof(const UniValue& params, bool fHelp)
+UniValue gettxoutproof(const JSONRPCRequest& request)
{
- if (fHelp || (params.size() != 1 && params.size() != 2))
- throw runtime_error(
+ if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
+ 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"
" \"txid\" (string) A transaction hash\n"
" ,...\n"
" ]\n"
- "2. \"block hash\" (string, optional) If specified, looks for txid in the block with this hash\n"
+ "2. \"blockhash\" (string, optional) If specified, looks for txid in the block with this hash\n"
"\nResult:\n"
"\"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 = params[0].get_array();
+ 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;
}
@@ -261,9 +212,9 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
CBlockIndex* pblockindex = NULL;
uint256 hashBlock;
- if (params.size() > 1)
+ if (request.params.size() > 1)
{
- hashBlock = uint256S(params[1].get_str());
+ hashBlock = uint256S(request.params[1].get_str());
if (!mapBlockIndex.count(hashBlock))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
pblockindex = mapBlockIndex[hashBlock];
@@ -275,7 +226,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
if (pblockindex == NULL)
{
- CTransaction tx;
+ CTransactionRef tx;
if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
if (!mapBlockIndex.count(hashBlock))
@@ -288,8 +239,8 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
unsigned int ntxFound = 0;
- BOOST_FOREACH(const CTransaction&tx, block.vtx)
- if (setTxids.count(tx.GetHash()))
+ for (const auto& tx : block.vtx)
+ 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");
@@ -301,10 +252,10 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
return strHex;
}
-UniValue verifytxoutproof(const UniValue& params, bool fHelp)
+UniValue verifytxoutproof(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1)
+ 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"
@@ -314,14 +265,14 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\n"
);
- CDataStream ssMB(ParseHexV(params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
+ CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
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;
@@ -335,10 +286,10 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
return res;
}
-UniValue createrawtransaction(const UniValue& params, bool fHelp)
+UniValue createrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
+ throw std::runtime_error(
"createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime )\n"
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
"Outputs can be addresses or data.\n"
@@ -347,43 +298,43 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
"it is not stored in the wallet or transmitted to the network.\n"
"\nArguments:\n"
- "1. \"transactions\" (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"
- " \"vout\":n (numeric, required) The output number\n"
- " \"sequence\":n (numeric, optional) The sequence number\n"
- " }\n"
+ " \"vout\":n, (numeric, required) The output number\n"
+ " \"sequence\":n (numeric, optional) The sequence number\n"
+ " } \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"
+ " \"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"
+ "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
"\nResult:\n"
- "\"transaction\" (string) hex string of the transaction\n"
+ "\"transaction\" (string) hex string of the transaction\n"
- "\nExamples\n"
+ "\nExamples:\n"
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"")
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"data\\\":\\\"00010203\\\"}\"")
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
- if (params[0].isNull() || params[1].isNull())
+ RPCTypeCheck(request.params, boost::assign::list_of(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");
- UniValue inputs = params[0].get_array();
- UniValue sendTo = params[1].get_obj();
+ UniValue inputs = request.params[0].get_array();
+ UniValue sendTo = request.params[1].get_obj();
CMutableTransaction rawTx;
- if (params.size() > 2 && !params[2].isNull()) {
- int64_t nLockTime = params[2].get_int64();
+ if (request.params.size() > 2 && !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;
@@ -419,9 +370,9 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
rawTx.vin.push_back(in);
}
- set<CBitcoinAddress> setAddress;
- vector<string> addrList = sendTo.getKeys();
- BOOST_FOREACH(const string& name_, addrList) {
+ std::set<CBitcoinAddress> setAddress;
+ std::vector<std::string> addrList = sendTo.getKeys();
+ BOOST_FOREACH(const std::string& name_, addrList) {
if (name_ == "data") {
std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),"Data");
@@ -431,10 +382,10 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
} else {
CBitcoinAddress address(name_);
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
+ 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_);
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
setAddress.insert(address);
CScript scriptPubKey = GetScriptForDestination(address.Get());
@@ -448,15 +399,15 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
return EncodeHexTx(rawTx);
}
-UniValue decoderawtransaction(const UniValue& params, bool fHelp)
+UniValue decoderawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
"decoderawtransaction \"hexstring\"\n"
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n"
"\nArguments:\n"
- "1. \"hex\" (string, required) The transaction hex string\n"
+ "1. \"hexstring\" (string, required) The transaction hex string\n"
"\nResult:\n"
"{\n"
@@ -504,27 +455,27 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
- CTransaction tx;
+ CMutableTransaction mtx;
- if (!DecodeHexTx(tx, params[0].get_str(), true))
+ if (!DecodeHexTx(mtx, request.params[0].get_str(), true))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
UniValue result(UniValue::VOBJ);
- TxToJSON(tx, uint256(), result);
+ TxToUniv(CTransaction(std::move(mtx)), uint256(), result);
return result;
}
-UniValue decodescript(const UniValue& params, bool fHelp)
+UniValue decodescript(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "decodescript \"hex\"\n"
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
+ "decodescript \"hexstring\"\n"
"\nDecode a hex-encoded script.\n"
"\nArguments:\n"
- "1. \"hex\" (string) the hex encoded script\n"
+ "1. \"hexstring\" (string) the hex encoded script\n"
"\nResult:\n"
"{\n"
" \"asm\":\"asm\", (string) Script public key\n"
@@ -535,26 +486,34 @@ UniValue decodescript(const UniValue& params, bool fHelp)
" \"address\" (string) bitcoin address\n"
" ,...\n"
" ],\n"
- " \"p2sh\",\"address\" (string) script address\n"
+ " \"p2sh\",\"address\" (string) address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("decodescript", "\"hexstring\"")
+ HelpExampleRpc("decodescript", "\"hexstring\"")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
UniValue r(UniValue::VOBJ);
CScript script;
- if (params[0].get_str().size() > 0){
- vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
+ if (request.params[0].get_str().size() > 0){
+ 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");
+
+ 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", CBitcoinAddress(CScriptID(script)).ToString()));
return r;
}
@@ -570,10 +529,14 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
vErrorsRet.push_back(entry);
}
-UniValue signrawtransaction(const UniValue& params, bool fHelp)
+UniValue signrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 4)
- throw runtime_error(
+#ifdef ENABLE_WALLET
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+#endif
+
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
+ 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"
@@ -581,7 +544,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
"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"
@@ -597,7 +560,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
" }\n"
" ,...\n"
" ]\n"
- "3. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\n"
+ "3. \"privkeys\" (string, optional) A json array of base58-encoded private keys for signing\n"
" [ (json array of strings, or 'null' if none provided)\n"
" \"privatekey\" (string) private key in base58-encoding\n"
" ,...\n"
@@ -632,15 +595,15 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
);
#ifdef ENABLE_WALLET
- LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+ LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
- vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
+ std::vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
- vector<CMutableTransaction> txVariants;
+ std::vector<CMutableTransaction> txVariants;
while (!ssData.empty()) {
try {
CMutableTransaction tx;
@@ -679,9 +642,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
- if (params.size() > 2 && !params[2].isNull()) {
+ if (request.params.size() > 2 && !request.params[2].isNull()) {
fGivenKeys = true;
- UniValue keys = params[2].get_array();
+ UniValue keys = request.params[2].get_array();
for (unsigned int idx = 0; idx < keys.size(); idx++) {
UniValue k = keys[idx];
CBitcoinSecret vchSecret;
@@ -695,13 +658,14 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
}
}
#ifdef ENABLE_WALLET
- else if (pwalletMain)
- EnsureWalletIsUnlocked();
+ else if (pwallet) {
+ EnsureWalletIsUnlocked(pwallet);
+ }
#endif
// Add previous txouts given in the RPC call:
- if (params.size() > 1 && !params[1].isNull()) {
- UniValue prevTxs = params[1].get_array();
+ if (request.params.size() > 1 && !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];
if (!p.isObject())
@@ -722,13 +686,13 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
if (nOut < 0)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
- vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
+ 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");
+ std::string err("Previous output scriptPubKey mismatch:\n");
err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey);
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
@@ -754,7 +718,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
});
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);
}
@@ -763,23 +727,23 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
}
#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 (params.size() > 3 && !params[3].isNull()) {
- static map<string, int> mapSigHashValues =
+ if (request.params.size() > 3 && !request.params[3].isNull()) {
+ static std::map<std::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))
+ (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))
;
- string strHashType = params[3].get_str();
+ std::string strHashType = request.params[3].get_str();
if (mapSigHashValues.count(strHashType))
nHashType = mapSigHashValues[strHashType];
else
@@ -812,13 +776,15 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
// ... and merge in other signatures:
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
- sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
+ if (txv.vin.size() > i) {
+ sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
+ }
}
UpdateTransaction(mergedTx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK;
- if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx.wit.vtxinwit.size() > i ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
+ if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
}
}
@@ -834,10 +800,10 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
return result;
}
-UniValue sendrawtransaction(const UniValue& params, bool fHelp)
+UniValue sendrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ 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"
@@ -858,16 +824,18 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
// parse hex string from parameter
- CTransaction tx;
- if (!DecodeHexTx(tx, params[0].get_str()))
+ CMutableTransaction mtx;
+ if (!DecodeHexTx(mtx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
- uint256 hashTx = tx.GetHash();
+ CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
+ const uint256& hashTx = tx->GetHash();
+ bool fLimitFree = true;
CAmount nMaxRawTxFee = maxTxFee;
- if (params.size() > 1 && params[1].get_bool())
+ if (request.params.size() > 1 && request.params[1].get_bool())
nMaxRawTxFee = 0;
CCoinsViewCache &view = *pcoinsTip;
@@ -878,7 +846,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, nMaxRawTxFee)) {
+ if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, NULL, false, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
@@ -891,27 +859,33 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
- RelayTransaction(tx);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ CInv inv(MSG_TX, hashTx);
+ g_connman->ForEachNode([&inv](CNode* pnode)
+ {
+ pnode->PushInventory(inv);
+ });
return hashTx.GetHex();
}
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "getrawtransaction", &getrawtransaction, true },
- { "rawtransactions", "createrawtransaction", &createrawtransaction, true },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true },
- { "rawtransactions", "decodescript", &decodescript, true },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false },
- { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */
-
- { "blockchain", "gettxoutproof", &gettxoutproof, true },
- { "blockchain", "verifytxoutproof", &verifytxoutproof, true },
+ { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} },
+ { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","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"} },
};
-void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC)
+void RegisterRawTransactionRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/register.h b/src/rpc/register.h
index 01aa58a25d..49aee2365f 100644
--- a/src/rpc/register.h
+++ b/src/rpc/register.h
@@ -20,13 +20,13 @@ void RegisterMiningRPCCommands(CRPCTable &tableRPC);
/** Register raw transaction RPC commands */
void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);
-static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC)
+static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
{
- RegisterBlockchainRPCCommands(tableRPC);
- RegisterNetRPCCommands(tableRPC);
- RegisterMiscRPCCommands(tableRPC);
- RegisterMiningRPCCommands(tableRPC);
- RegisterRawTransactionRPCCommands(tableRPC);
+ RegisterBlockchainRPCCommands(t);
+ RegisterNetRPCCommands(t);
+ RegisterMiscRPCCommands(t);
+ RegisterMiningRPCCommands(t);
+ RegisterRawTransactionRPCCommands(t);
}
#endif
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 23149baa6d..ea93e8cc74 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -1,11 +1,12 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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 "rpc/server.h"
#include "base58.h"
+#include "fs.h"
#include "init.h"
#include "random.h"
#include "sync.h"
@@ -16,17 +17,16 @@
#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>
-using namespace RPCServer;
-using namespace std;
+#include <memory> // for unique_ptr
+#include <unordered_map>
static bool fRPCRunning = false;
static bool fRPCInWarmup = true;
@@ -34,16 +34,14 @@ static std::string rpcWarmupStatus("RPC server started");
static CCriticalSection cs_rpcWarmup;
/* Timer-creating functions */
static RPCTimerInterface* timerInterface = NULL;
-/* Map of name to timer.
- * @note Can be changed to std::unique_ptr when C++11 */
-static std::map<std::string, boost::shared_ptr<RPCTimerBase> > deadlineTimers;
+/* Map of name to timer. */
+static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
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)
@@ -61,13 +59,8 @@ 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;
@@ -77,18 +70,22 @@ void RPCTypeCheck(const UniValue& params,
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)
{
@@ -98,7 +95,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);
}
@@ -106,11 +103,11 @@ void RPCTypeCheckObj(const UniValue& o,
if (fStrict)
{
- BOOST_FOREACH(const string& k, o.getKeys())
+ BOOST_FOREACH(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);
}
}
@@ -139,31 +136,33 @@ UniValue ValueFromAmount(const CAmount& amount)
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
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
+ if (64 != strHex.length())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length()));
uint256 result;
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);
}
@@ -172,40 +171,41 @@ 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();
+
+ BOOST_FOREACH(const PAIRTYPE(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
{
- UniValue params;
rpcfn_type pfn = pcmd->actor;
if (setDone.insert(pfn).second)
- (*pfn)(params, true);
+ (*pfn)(jreq);
}
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)
@@ -213,7 +213,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";
}
@@ -227,10 +227,10 @@ std::string CRPCTable::help(const std::string& strCommand) const
return strRet;
}
-UniValue help(const UniValue& params, bool fHelp)
+UniValue help(const JSONRPCRequest& jsonRequest)
{
- if (fHelp || params.size() > 1)
- throw runtime_error(
+ if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
+ throw std::runtime_error(
"help ( \"command\" )\n"
"\nList all commands, or get help for a specified command.\n"
"\nArguments:\n"
@@ -239,19 +239,19 @@ UniValue help(const UniValue& params, bool fHelp)
"\"text\" (string) The help text\n"
);
- string strCommand;
- if (params.size() > 0)
- strCommand = params[0].get_str();
+ std::string strCommand;
+ if (jsonRequest.params.size() > 0)
+ strCommand = jsonRequest.params[0].get_str();
- return tableRPC.help(strCommand);
+ return tableRPC.help(strCommand, jsonRequest);
}
-UniValue stop(const UniValue& params, bool fHelp)
+UniValue stop(const JSONRPCRequest& jsonRequest)
{
// Accept the deprecated and ignored 'detach' boolean argument
- if (fHelp || params.size() > 1)
- throw runtime_error(
+ if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
+ throw std::runtime_error(
"stop\n"
"\nStop Bitcoin server.");
// Event loop will exit after current HTTP requests have been handled, so
@@ -264,11 +264,11 @@ UniValue stop(const UniValue& params, bool fHelp)
* Call Table
*/
static const CRPCCommand vRPCCommands[] =
-{ // category name actor (function) okSafeMode
- // --------------------- ------------------------ ----------------------- ----------
+{ // category name actor (function) okSafe argNames
+ // --------------------- ------------------------ ----------------------- ------ ----------
/* Overall control/query calls */
- { "control", "help", &help, true },
- { "control", "stop", &stop, true },
+ { "control", "help", &help, true, {"command"} },
+ { "control", "stop", &stop, true, {} },
};
CRPCTable::CRPCTable()
@@ -285,7 +285,7 @@ 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 (*it).second;
@@ -297,7 +297,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;
@@ -307,7 +307,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;
@@ -315,15 +315,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();
}
@@ -353,7 +354,7 @@ bool RPCIsInWarmup(std::string *outStatus)
return fRPCInWarmup;
}
-void JSONRequest::parse(const UniValue& valRequest)
+void JSONRPCRequest::parse(const UniValue& valRequest)
{
// Parse request
if (!valRequest.isObject())
@@ -370,28 +371,27 @@ void JSONRequest::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");
- if (valParams.isArray())
- params = valParams.get_array();
+ if (valParams.isArray() || valParams.isObject())
+ params = valParams;
else if (valParams.isNull())
params = UniValue(UniValue::VARR);
else
- throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
+ throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
}
static UniValue JSONRPCExecOne(const UniValue& req)
{
UniValue rpc_result(UniValue::VOBJ);
- JSONRequest jreq;
+ JSONRPCRequest jreq;
try {
jreq.parse(req);
- UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
+ UniValue result = tableRPC.execute(jreq);
rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
}
catch (const UniValue& objError)
@@ -416,7 +416,57 @@ std::string JSONRPCExecBatch(const UniValue& vReq)
return ret.write() + "\n";
}
-UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params) const
+/**
+ * Process named arguments into a vector of positional arguments, based on the
+ * passed-in specification for the RPC call's arguments.
+ */
+static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames)
+{
+ JSONRPCRequest out = in;
+ out.params = UniValue(UniValue::VARR);
+ // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if
+ // there is an unknown one.
+ const std::vector<std::string>& keys = in.params.getKeys();
+ const std::vector<UniValue>& values = in.params.getValues();
+ std::unordered_map<std::string, const UniValue*> argsIn;
+ for (size_t i=0; i<keys.size(); ++i) {
+ argsIn[keys[i]] = &values[i];
+ }
+ // Process expected parameters.
+ int hole = 0;
+ 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,
+ // but not at the end (for backwards compatibility with calls
+ // that act based on number of specified parameters).
+ out.params.push_back(UniValue());
+ }
+ hole = 0;
+ out.params.push_back(*fr->second);
+ argsIn.erase(fr);
+ } else {
+ hole += 1;
+ }
+ }
+ // If there are still arguments in the argsIn map, this is an error.
+ if (!argsIn.empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown named parameter " + argsIn.begin()->first);
+ }
+ // Return request with named arguments transformed to positional arguments
+ return out;
+}
+
+UniValue CRPCTable::execute(const JSONRPCRequest &request) const
{
// Return immediately if in warmup
{
@@ -426,7 +476,7 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params
}
// Find method
- const CRPCCommand *pcmd = tableRPC[strMethod];
+ const CRPCCommand *pcmd = tableRPC[request.strMethod];
if (!pcmd)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
@@ -434,15 +484,17 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params
try
{
- // Execute
- return pcmd->actor(params, false);
+ // Execute, convert arguments to array if necessary
+ if (request.params.isObject()) {
+ return pcmd->actor(transformNamedArguments(request, pcmd->argNames));
+ } else {
+ return pcmd->actor(request);
+ }
}
catch (const std::exception& e)
{
throw JSONRPCError(RPC_MISC_ERROR, e.what());
}
-
- g_rpcSignals.PostCommand(*pcmd);
}
std::vector<std::string> CRPCTable::listCommands() const
@@ -489,8 +541,16 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6
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());
- deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))));
+ 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)
+ flag |= SERIALIZE_TRANSACTION_NO_WITNESS;
+ return flag;
}
CRPCTable tableRPC;
diff --git a/src/rpc/server.h b/src/rpc/server.h
index b5ccc153d0..34a9d3c24c 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -19,6 +19,8 @@
#include <univalue.h>
+static const unsigned int DEFAULT_RPC_SERIALIZE_VERSION = 1;
+
class CRPCCommand;
namespace RPCServer
@@ -26,7 +28,6 @@ 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);
}
class CBlockIndex;
@@ -41,14 +42,17 @@ struct UniValueType {
UniValue::VType type;
};
-class JSONRequest
+class JSONRPCRequest
{
public:
UniValue id;
std::string strMethod;
UniValue params;
+ bool fHelp;
+ std::string URI;
+ std::string authUser;
- JSONRequest() { id = NullUniValue; }
+ JSONRPCRequest() { id = NullUniValue; params = NullUniValue; fHelp = false; }
void parse(const UniValue& valRequest);
};
@@ -64,7 +68,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
@@ -73,6 +77,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.
*/
@@ -122,7 +131,7 @@ void RPCUnsetTimerInterface(RPCTimerInterface *iface);
*/
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds);
-typedef UniValue(*rpcfn_type)(const UniValue& params, bool fHelp);
+typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);
class CRPCCommand
{
@@ -131,6 +140,7 @@ public:
std::string name;
rpcfn_type actor;
bool okSafeMode;
+ std::vector<std::string> argNames;
};
/**
@@ -143,16 +153,15 @@ 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.
- * @param method Method to execute
- * @param params UniValue Array of arguments (JSON objects)
+ * @param request The JSONRPCRequest to execute
* @returns Result of the call.
* @throws an exception (UniValue) when an error happens.
*/
- UniValue execute(const std::string &method, const UniValue &params) const;
+ UniValue execute(const JSONRPCRequest &request) const;
/**
* Returns a list of registered commands
@@ -180,19 +189,17 @@ 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);
+// Retrieves any serialization flags requested in command line argument
+int RPCSerializationFlags();
+
#endif // BITCOIN_RPCSERVER_H
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 52777b61f9..0c1cfa2718 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -23,7 +23,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
@@ -54,9 +56,10 @@ void CScheduler::serviceQueue()
#else
// Some boost versions have a conflicting overload of wait_until that returns void.
// Explicitly use a template here to avoid hitting that overload.
- while (!shouldStop() && !taskQueue.empty() &&
- newTaskScheduled.wait_until<>(lock, taskQueue.begin()->first) != boost::cv_status::timeout) {
- // Keep waiting until timeout
+ while (!shouldStop() && !taskQueue.empty()) {
+ boost::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first;
+ if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == boost::cv_status::timeout)
+ break; // Exit loop after timeout, it means we reached the time of the event
}
#endif
// If there are multiple threads, the queue can empty while we're waiting (another
@@ -103,20 +106,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,
diff --git a/src/scheduler.h b/src/scheduler.h
index 436659e58b..613fc1653f 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -10,7 +10,6 @@
// boost::thread / boost::function / boost::chrono should be ported to
// std::thread / std::function / std::chrono when we support C++11.
//
-#include <boost/function.hpp>
#include <boost/chrono/chrono.hpp>
#include <boost/thread.hpp>
#include <map>
@@ -23,7 +22,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 +38,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);
// 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.
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index 62fd9031f8..c4ab441e2c 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -23,7 +23,7 @@ public:
m_remaining(txToLen)
{}
- TxInputStream& read(char* pch, size_t nSize)
+ void read(char* pch, size_t nSize)
{
if (nSize > m_remaining)
throw std::ios_base::failure(std::string(__func__) + ": end of data");
@@ -37,16 +37,17 @@ public:
memcpy(pch, m_data, nSize);
m_remaining -= nSize;
m_data += nSize;
- return *this;
}
template<typename T>
TxInputStream& operator>>(T& obj)
{
- ::Unserialize(*this, obj, m_type, m_version);
+ ::Unserialize(*this, obj);
return *this;
}
+ int GetVersion() const { return m_version; }
+ int GetType() const { return m_type; }
private:
const int m_type;
const int m_version;
@@ -69,23 +70,32 @@ struct ECCryptoClosure
ECCryptoClosure instance_of_eccryptoclosure;
}
+/** Check that all specified flags are part of the libconsensus interface. */
+static bool verify_flags(unsigned int flags)
+{
+ return (flags & ~(bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL)) == 0;
+}
+
static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
const unsigned char *txTo , unsigned int txToLen,
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
{
+ if (!verify_flags(flags)) {
+ return bitcoinconsensus_ERR_INVALID_FLAGS;
+ }
try {
TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen);
- CTransaction tx;
- stream >> tx;
+ CTransaction tx(deserialize, stream);
if (nIn >= tx.vin.size())
return set_error(err, bitcoinconsensus_ERR_TX_INDEX);
- if (tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) != txToLen)
+ if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen)
return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
// Regardless of the verification result, the tx did not error.
set_error(err, bitcoinconsensus_ERR_OK);
- return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount), NULL);
+ PrecomputedTransactionData txdata(tx);
+ return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), NULL);
} 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 6f868d0d6d..1bef4fe9e9 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -42,6 +42,7 @@ typedef enum bitcoinconsensus_error_t
bitcoinconsensus_ERR_TX_SIZE_MISMATCH,
bitcoinconsensus_ERR_TX_DESERIALIZE,
bitcoinconsensus_ERR_AMOUNT_REQUIRED,
+ bitcoinconsensus_ERR_INVALID_FLAGS,
} bitcoinconsensus_error;
/** Script verification flags */
@@ -50,8 +51,13 @@ enum
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY = (1U << 4), // enforce NULLDUMMY (BIP147)
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65)
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10), // enable CHECKSEQUENCEVERIFY (BIP112)
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS = (1U << 11), // enable WITNESS (BIP141)
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL = bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG |
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY |
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS
};
/// Returns 1 if the input nIn of the serialized transaction pointed to by
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index bc027e9f0c..f4e5313a78 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -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 {
@@ -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();
}
@@ -79,8 +77,20 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
return false;
}
} else {
- // Non-canonical public key: neither compressed nor uncompressed
- return false;
+ // Non-canonical public key: neither compressed nor uncompressed
+ return false;
+ }
+ return true;
+}
+
+bool static IsCompressedPubKey(const valtype &vchPubKey) {
+ if (vchPubKey.size() != 33) {
+ // Non-canonical public key: invalid length for compressed key
+ return false;
+ }
+ if (vchPubKey[0] != 0x02 && vchPubKey[0] != 0x03) {
+ // Non-canonical public key: invalid prefix for compressed key
+ return false;
}
return true;
}
@@ -182,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) {
@@ -199,10 +209,14 @@ bool CheckSignatureEncoding(const vector<unsigned char> &vchSig, unsigned int fl
return true;
}
-bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) {
- if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) {
+bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {
+ if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
}
+ // Only compressed keys are accepted in segwit
+ if ((flags & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) != 0 && sigversion == SIGVERSION_WITNESS_V0 && !IsCompressedPubKey(vchPubKey)) {
+ return set_error(serror, SCRIPT_ERR_WITNESS_PUBKEYTYPE);
+ }
return true;
}
@@ -229,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();
@@ -244,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);
@@ -428,6 +442,12 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if (stack.size() < 1)
return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
valtype& vch = stacktop(-1);
+ if (sigversion == SIGVERSION_WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) {
+ if (vch.size() > 1)
+ return set_error(serror, SCRIPT_ERR_MINIMALIF);
+ if (vch.size() == 1 && vch[0] != 1)
+ return set_error(serror, SCRIPT_ERR_MINIMALIF);
+ }
fValue = CastToBool(vch);
if (opcode == OP_NOTIF)
fValue = !fValue;
@@ -834,15 +854,15 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
valtype& vch = stacktop(-1);
valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);
if (opcode == OP_RIPEMD160)
- CRIPEMD160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));
+ CRIPEMD160().Write(vch.data(), vch.size()).Finalize(vchHash.data());
else if (opcode == OP_SHA1)
- CSHA1().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));
+ CSHA1().Write(vch.data(), vch.size()).Finalize(vchHash.data());
else if (opcode == OP_SHA256)
- CSHA256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));
+ CSHA256().Write(vch.data(), vch.size()).Finalize(vchHash.data());
else if (opcode == OP_HASH160)
- CHash160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));
+ CHash160().Write(vch.data(), vch.size()).Finalize(vchHash.data());
else if (opcode == OP_HASH256)
- CHash256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));
+ CHash256().Write(vch.data(), vch.size()).Finalize(vchHash.data());
popstack(stack);
stack.push_back(vchHash);
}
@@ -868,17 +888,20 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);
- // Drop the signature, since there's no way for a signature to sign itself
+ // Drop the signature in pre-segwit scripts but not segwit scripts
if (sigversion == SIGVERSION_BASE) {
scriptCode.FindAndDelete(CScript(vchSig));
}
- if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
+ if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
//serror is set
return false;
}
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
+ if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size())
+ return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
+
popstack(stack);
popstack(stack);
stack.push_back(fSuccess ? vchTrue : vchFalse);
@@ -908,6 +931,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if (nOpCount > MAX_OPS_PER_SCRIPT)
return set_error(serror, SCRIPT_ERR_OP_COUNT);
int ikey = ++i;
+ // ikey2 is the position of last non-signature item in the stack. Top stack item = 1.
+ // With SCRIPT_VERIFY_NULLFAIL, this is used for cleanup if operation fails.
+ int ikey2 = nKeysCount + 2;
i += nKeysCount;
if ((int)stack.size() < i)
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
@@ -923,7 +949,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);
- // Drop the signatures, since there's no way for a signature to sign itself
+ // Drop the signature in pre-segwit scripts but not segwit scripts
for (int k = 0; k < nSigsCount; k++)
{
valtype& vchSig = stacktop(-isig-k);
@@ -941,7 +967,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Note how this makes the exact order of pubkey/signature evaluation
// distinguishable by CHECKMULTISIG NOT if the STRICTENC flag is set.
// See the script_(in)valid tests for details.
- if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
+ if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
// serror is set
return false;
}
@@ -964,8 +990,14 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
}
// Clean up stack of actual arguments
- while (i-- > 1)
+ while (i-- > 1) {
+ // If the operation failed, we require that all signatures must be empty vector
+ if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && !ikey2 && stacktop(-1).size())
+ return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
+ if (ikey2 > 0)
+ ikey2--;
popstack(stack);
+ }
// A bug causes CHECKMULTISIG to consume one extra argument
// whose contents were not checked in any way.
@@ -1035,7 +1067,7 @@ public:
/** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */
template<typename S>
- void SerializeScriptCode(S &s, int nType, int nVersion) const {
+ void SerializeScriptCode(S &s) const {
CScript::const_iterator it = scriptCode.begin();
CScript::const_iterator itBegin = it;
opcodetype opcode;
@@ -1058,59 +1090,90 @@ public:
/** Serialize an input of txTo */
template<typename S>
- void SerializeInput(S &s, unsigned int nInput, int nType, int nVersion) const {
+ void SerializeInput(S &s, unsigned int nInput) const {
// In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized
if (fAnyoneCanPay)
nInput = nIn;
// Serialize the prevout
- ::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion);
+ ::Serialize(s, txTo.vin[nInput].prevout);
// Serialize the script
if (nInput != nIn)
// Blank out other inputs' signatures
- ::Serialize(s, CScriptBase(), nType, nVersion);
+ ::Serialize(s, CScriptBase());
else
- SerializeScriptCode(s, nType, nVersion);
+ SerializeScriptCode(s);
// Serialize the nSequence
if (nInput != nIn && (fHashSingle || fHashNone))
// let the others update at will
- ::Serialize(s, (int)0, nType, nVersion);
+ ::Serialize(s, (int)0);
else
- ::Serialize(s, txTo.vin[nInput].nSequence, nType, nVersion);
+ ::Serialize(s, txTo.vin[nInput].nSequence);
}
/** Serialize an output of txTo */
template<typename S>
- void SerializeOutput(S &s, unsigned int nOutput, int nType, int nVersion) const {
+ void SerializeOutput(S &s, unsigned int nOutput) const {
if (fHashSingle && nOutput != nIn)
// Do not lock-in the txout payee at other indices as txin
- ::Serialize(s, CTxOut(), nType, nVersion);
+ ::Serialize(s, CTxOut());
else
- ::Serialize(s, txTo.vout[nOutput], nType, nVersion);
+ ::Serialize(s, txTo.vout[nOutput]);
}
/** Serialize txTo */
template<typename S>
- void Serialize(S &s, int nType, int nVersion) const {
+ void Serialize(S &s) const {
// Serialize nVersion
- ::Serialize(s, txTo.nVersion, nType, nVersion);
+ ::Serialize(s, txTo.nVersion);
// Serialize vin
unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size();
::WriteCompactSize(s, nInputs);
for (unsigned int nInput = 0; nInput < nInputs; nInput++)
- SerializeInput(s, nInput, nType, nVersion);
+ SerializeInput(s, nInput);
// Serialize vout
unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size());
::WriteCompactSize(s, nOutputs);
for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++)
- SerializeOutput(s, nOutput, nType, nVersion);
+ SerializeOutput(s, nOutput);
// Serialize nLockTime
- ::Serialize(s, txTo.nLockTime, nType, nVersion);
+ ::Serialize(s, txTo.nLockTime);
}
};
+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;
+ }
+ 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;
+ }
+ 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];
+ }
+ return ss.GetHash();
+}
+
} // anon namespace
-uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion)
+PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
+{
+ hashPrevouts = GetPrevoutHash(txTo);
+ hashSequence = GetSequenceHash(txTo);
+ hashOutputs = GetOutputsHash(txTo);
+}
+
+uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
if (sigversion == SIGVERSION_WITNESS_V0) {
uint256 hashPrevouts;
@@ -1118,27 +1181,16 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
uint256 hashOutputs;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].prevout;
- }
- hashPrevouts = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
}
if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].nSequence;
- }
- hashSequence = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
}
+
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vout.size(); n++) {
- ss << txTo.vout[n];
- }
- hashOutputs = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CHashWriter ss(SER_GETHASH, 0);
ss << txTo.vout[nIn];
@@ -1196,20 +1248,20 @@ 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();
vchSig.pop_back();
- uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
+ uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
if (!VerifySignature(vchSig, pubkey, sighash))
return false;
@@ -1301,7 +1353,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) {
@@ -1366,7 +1418,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;
@@ -1504,7 +1556,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 bd2f211663..60f6f711e6 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -94,17 +94,36 @@ enum
// Making v1-v16 witness program non-standard
//
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1U << 12),
+
+ // Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector
+ //
+ SCRIPT_VERIFY_MINIMALIF = (1U << 13),
+
+ // Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
+ //
+ SCRIPT_VERIFY_NULLFAIL = (1U << 14),
+
+ // Public keys in segregated witness scripts must be compressed
+ //
+ SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
};
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
+struct PrecomputedTransactionData
+{
+ uint256 hashPrevouts, hashSequence, hashOutputs;
+
+ PrecomputedTransactionData(const CTransaction& tx);
+};
+
enum SigVersion
{
SIGVERSION_BASE = 0,
SIGVERSION_WITNESS_V0 = 1,
};
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion);
+uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL);
class BaseSignatureChecker
{
@@ -133,12 +152,14 @@ private:
const CTransaction* txTo;
unsigned int nIn;
const CAmount amount;
+ const PrecomputedTransactionData* txdata;
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) {}
+ 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, 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;
@@ -150,7 +171,7 @@ 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);
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 0bf180341e..a4743281b1 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -13,11 +13,9 @@
#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)
@@ -29,15 +27,27 @@ unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
return nResult;
}
-isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
+isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion sigversion)
+{
+ bool isInvalid = false;
+ return IsMine(keystore, scriptPubKey, isInvalid, sigversion);
+}
+
+isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, SigVersion sigversion)
+{
+ bool isInvalid = false;
+ return IsMine(keystore, dest, isInvalid, sigversion);
+}
+
+isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest, bool& isInvalid, SigVersion sigversion)
{
CScript script = GetScriptForDestination(dest);
- return IsMine(keystore, script);
+ return IsMine(keystore, script, isInvalid, sigversion);
}
-isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
+isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion)
{
- vector<valtype> vSolutions;
+ std::vector<valtype> vSolutions;
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions)) {
if (keystore.HaveWatchOnly(scriptPubKey))
@@ -53,12 +63,35 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
break;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
+ if (sigversion != SIGVERSION_BASE && vSolutions[0].size() != 33) {
+ isInvalid = true;
+ return ISMINE_NO;
+ }
if (keystore.HaveKey(keyID))
return ISMINE_SPENDABLE;
break;
- case TX_PUBKEYHASH:
case TX_WITNESS_V0_KEYHASH:
+ {
+ if (!keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
+ // We do not support bare witness outputs unless the P2SH version of it would be
+ // acceptable as well. This protects against matching before segwit activates.
+ // This also applies to the P2WSH case.
+ break;
+ }
+ isminetype ret = ::IsMine(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), isInvalid, SIGVERSION_WITNESS_V0);
+ if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid))
+ return ret;
+ break;
+ }
+ case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
+ if (sigversion != SIGVERSION_BASE) {
+ CPubKey pubkey;
+ if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
+ isInvalid = true;
+ return ISMINE_NO;
+ }
+ }
if (keystore.HaveKey(keyID))
return ISMINE_SPENDABLE;
break;
@@ -67,21 +100,24 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
CScript subscript;
if (keystore.GetCScript(scriptID, subscript)) {
- isminetype ret = IsMine(keystore, subscript);
- if (ret == ISMINE_SPENDABLE)
+ isminetype ret = IsMine(keystore, subscript, isInvalid);
+ if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid))
return ret;
}
break;
}
case TX_WITNESS_V0_SCRIPTHASH:
{
+ if (!keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
+ break;
+ }
uint160 hash;
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin());
CScriptID scriptID = CScriptID(hash);
CScript subscript;
if (keystore.GetCScript(scriptID, subscript)) {
- isminetype ret = IsMine(keystore, subscript);
- if (ret == ISMINE_SPENDABLE)
+ isminetype ret = IsMine(keystore, subscript, isInvalid, SIGVERSION_WITNESS_V0);
+ if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid))
return ret;
}
break;
@@ -94,7 +130,15 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
// 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) {
+ isInvalid = true;
+ return ISMINE_NO;
+ }
+ }
+ }
if (HaveKeys(keys, keystore) == keys.size())
return ISMINE_SPENDABLE;
break;
diff --git a/src/script/ismine.h b/src/script/ismine.h
index 4b7db8802b..1aa5937b34 100644
--- a/src/script/ismine.h
+++ b/src/script/ismine.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -28,7 +28,14 @@ enum isminetype
/** used for bitflags of isminetype */
typedef uint8_t isminefilter;
-isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
-isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
+/* isInvalid becomes true when the script is found invalid by consensus or policy. This will terminate the recursion
+ * and return a ISMINE_NO immediately, as an invalid script should never be considered as "mine". This is needed as
+ * different SIGVERSION may have different network rules. Currently the only use of isInvalid is indicate uncompressed
+ * keys in SIGVERSION_WITNESS_V0 script, but could also be used in similar cases in the future
+ */
+isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion = SIGVERSION_BASE);
+isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion = SIGVERSION_BASE);
+isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, bool& isInvalid, SigVersion = SIGVERSION_BASE);
+isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, SigVersion = SIGVERSION_BASE);
#endif // BITCOIN_SCRIPT_ISMINE_H
diff --git a/src/script/script.cpp b/src/script/script.cpp
index ddf6775569..70eb8a139b 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -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);
}
diff --git a/src/script/script.h b/src/script/script.h
index 278774d32e..d7aaa04f80 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -394,7 +394,6 @@ protected:
}
public:
CScript() { }
- CScript(const CScript& b) : CScriptBase(b.begin(), b.end()) { }
CScript(const_iterator pbegin, const_iterator pend) : CScriptBase(pbegin, pend) { }
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) { }
@@ -449,16 +448,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;
@@ -656,6 +655,8 @@ struct CScriptWitness
bool IsNull() const { return stack.empty(); }
+ void SetNull() { stack.clear(); stack.shrink_to_fit(); }
+
std::string ToString() const;
};
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
index cef807edcf..c9d13c92a8 100644
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// 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.
@@ -63,6 +63,10 @@ const char* ScriptErrorString(const ScriptError serror)
return "Non-canonical signature: S value is unnecessarily high";
case SCRIPT_ERR_SIG_NULLDUMMY:
return "Dummy CHECKMULTISIG argument must be zero";
+ case SCRIPT_ERR_MINIMALIF:
+ return "OP_IF/NOTIF argument must be minimal";
+ case SCRIPT_ERR_SIG_NULLFAIL:
+ return "Signature must be zero for failed CHECK(MULTI)SIG operation";
case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS:
return "NOPx reserved for soft-fork upgrades";
case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM:
@@ -81,6 +85,8 @@ const char* ScriptErrorString(const ScriptError serror)
return "Witness requires only-redeemscript scriptSig";
case SCRIPT_ERR_WITNESS_UNEXPECTED:
return "Witness provided for non-witness script";
+ case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
+ return "Using non-compressed keys in segwit";
case SCRIPT_ERR_UNKNOWN_ERROR:
case SCRIPT_ERR_ERROR_COUNT:
default: break;
diff --git a/src/script/script_error.h b/src/script/script_error.h
index 09dc6945ad..3200e94707 100644
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// 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.
@@ -39,7 +39,7 @@ typedef enum ScriptError_t
SCRIPT_ERR_NEGATIVE_LOCKTIME,
SCRIPT_ERR_UNSATISFIED_LOCKTIME,
- /* BIP62 */
+ /* Malleability */
SCRIPT_ERR_SIG_HASHTYPE,
SCRIPT_ERR_SIG_DER,
SCRIPT_ERR_MINIMALDATA,
@@ -48,6 +48,8 @@ typedef enum ScriptError_t
SCRIPT_ERR_SIG_NULLDUMMY,
SCRIPT_ERR_PUBKEYTYPE,
SCRIPT_ERR_CLEANSTACK,
+ SCRIPT_ERR_MINIMALIF,
+ SCRIPT_ERR_SIG_NULLFAIL,
/* softfork safeness */
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS,
@@ -60,6 +62,7 @@ typedef enum ScriptError_t
SCRIPT_ERR_WITNESS_MALLEATED,
SCRIPT_ERR_WITNESS_MALLEATED_P2SH,
SCRIPT_ERR_WITNESS_UNEXPECTED,
+ SCRIPT_ERR_WITNESS_PUBKEYTYPE,
SCRIPT_ERR_ERROR_COUNT
} ScriptError;
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index bdc0bfdc1c..7bb8d9941b 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -11,23 +11,10 @@
#include "uint256.h"
#include "util.h"
+#include "cuckoocache.h"
#include <boost/thread.hpp>
-#include <boost/unordered_set.hpp>
namespace {
-
-/**
- * We're hashing a nonce into the entries themselves, so we don't need extra
- * blinding in the set hash computation.
- */
-class CSignatureCacheHasher
-{
-public:
- size_t operator()(const uint256& key) const {
- return key.GetCheapHash();
- }
-};
-
/**
* Valid signature cache, to avoid doing expensive ECDSA signature checking
* twice for every transaction (once when accepted into memory pool, and
@@ -38,11 +25,10 @@ class CSignatureCache
private:
//! Entries are SHA256(nonce || signature hash || public key || signature):
uint256 nonce;
- typedef boost::unordered_set<uint256, CSignatureCacheHasher> map_type;
+ typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;
map_type setValid;
boost::shared_mutex cs_sigcache;
-
public:
CSignatureCache()
{
@@ -56,58 +42,53 @@ public:
}
bool
- Get(const uint256& entry)
+ Get(const uint256& entry, const bool erase)
{
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
- return setValid.count(entry);
+ return setValid.contains(entry, erase);
}
- void Erase(const uint256& entry)
+ void Set(uint256& entry)
{
boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
- setValid.erase(entry);
+ setValid.insert(entry);
}
-
- void Set(const uint256& entry)
+ uint32_t setup_bytes(size_t n)
{
- size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
- if (nMaxCacheSize <= 0) return;
-
- boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
- while (memusage::DynamicUsage(setValid) > nMaxCacheSize)
- {
- map_type::size_type s = GetRand(setValid.bucket_count());
- map_type::local_iterator it = setValid.begin(s);
- if (it != setValid.end(s)) {
- setValid.erase(*it);
- }
- }
-
- setValid.insert(entry);
+ return setValid.setup_bytes(n);
}
};
+/* In previous versions of this code, signatureCache was a local static variable
+ * in CachingTransactionSignatureChecker::VerifySignature. We initialize
+ * signatureCache outside of VerifySignature to avoid the atomic operation per
+ * call overhead associated with local static variables even though
+ * signatureCache could be made local to VerifySignature.
+*/
+static CSignatureCache signatureCache;
}
-bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
+// To be called once in AppInitMain/BasicTestingSetup to initialize the
+// signatureCache.
+void InitSignatureCache()
{
- static CSignatureCache signatureCache;
+ // 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, GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE)), 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);
+}
+bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
+{
uint256 entry;
signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey);
-
- if (signatureCache.Get(entry)) {
- if (!store) {
- signatureCache.Erase(entry);
- }
+ if (signatureCache.Get(entry, !store))
return true;
- }
-
if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash))
return false;
-
- if (store) {
+ if (store)
signatureCache.Set(entry);
- }
return true;
}
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 050bf8cc42..55cec4cc8d 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -10,21 +10,47 @@
#include <vector>
-// DoS prevention: limit cache size to less than 40MB (over 500000
-// entries on 64-bit systems).
-static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 40;
+// DoS prevention: limit cache size to 32MB (over 1000000 entries on 64-bit
+// 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) : TransactionSignatureChecker(txToIn, nInIn, amount), 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;
};
+void InitSignatureCache();
+
#endif // BITCOIN_SCRIPT_SIGCACHE_H
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 87f38d9c72..5682418546 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -14,8 +14,6 @@
#include <boost/foreach.hpp>
-using namespace std;
-
typedef std::vector<unsigned char> valtype;
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
@@ -26,6 +24,10 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
if (!keystore->GetKey(address, key))
return false;
+ // Signing with uncompressed keys is disabled in witness scripts
+ if (sigversion == SIGVERSION_WITNESS_V0 && !key.IsCompressed())
+ return false;
+
uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
if (!key.Sign(hash, vchSig))
return false;
@@ -35,14 +37,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];
@@ -69,7 +71,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;
@@ -121,7 +123,7 @@ 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) {
@@ -190,9 +192,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
SignatureData data;
assert(tx.vin.size() > nIn);
data.scriptSig = tx.vin[nIn].scriptSig;
- if (tx.wit.vtxinwit.size() > nIn) {
- data.scriptWitness = tx.wit.vtxinwit[nIn].scriptWitness;
- }
+ data.scriptWitness = tx.vin[nIn].scriptWitness;
return data;
}
@@ -200,10 +200,7 @@ void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const Signatur
{
assert(tx.vin.size() > nIn);
tx.vin[nIn].scriptSig = data.scriptSig;
- if (!data.scriptWitness.IsNull() || tx.wit.vtxinwit.size() > nIn) {
- tx.wit.vtxinwit.resize(tx.vin.size());
- tx.wit.vtxinwit[nIn].scriptWitness = data.scriptWitness;
- }
+ tx.vin[nIn].scriptWitness = data.scriptWitness;
}
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
@@ -229,12 +226,12 @@ 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;
+ std::set<valtype> allsigs;
BOOST_FOREACH(const valtype& v, sigs1)
{
if (!v.empty())
@@ -250,7 +247,7 @@ 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;
+ std::map<valtype, valtype> sigs;
BOOST_FOREACH(const valtype& sig, allsigs)
{
for (unsigned int i = 0; i < nPubKeys; i++)
@@ -307,7 +304,7 @@ 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)
@@ -341,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();
@@ -361,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;
@@ -384,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();
diff --git a/src/script/sign.h b/src/script/sign.h
index 6404b4523e..f3c0be4139 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -48,10 +48,10 @@ 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 signatyres. */
+/** A signature creator that just produces 72-byte empty signatures. */
class DummySignatureCreator : public BaseSignatureCreator {
public:
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index bb178f49fe..63f20b0993 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -12,9 +12,7 @@
#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;
@@ -40,20 +38,20 @@ const char* GetTxnOutputType(txnouttype t)
/**
* 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 +61,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;
}
@@ -102,7 +100,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
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 +179,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;
@@ -209,11 +207,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
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){
diff --git a/src/script/standard.h b/src/script/standard.h
index 72aaea0b7b..097e0c3748 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index e0b7b7a48a..87fea161ba 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -6,6 +6,7 @@ bench_schnorr_verify
bench_recover
bench_internal
tests
+exhaustive_tests
gen_context
*.exe
*.so
@@ -25,17 +26,24 @@ config.status
libtool
.deps/
.dirstamp
-build-aux/
*.lo
*.o
*~
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
src/ecmult_static_context.h
-m4/libtool.m4
-m4/ltoptions.m4
-m4/ltsugar.m4
-m4/ltversion.m4
-m4/lt~obsolete.m4
+build-aux/config.guess
+build-aux/config.sub
+build-aux/depcomp
+build-aux/install-sh
+build-aux/ltmain.sh
+build-aux/m4/libtool.m4
+build-aux/m4/lt~obsolete.m4
+build-aux/m4/ltoptions.m4
+build-aux/m4/ltsugar.m4
+build-aux/m4/ltversion.m4
+build-aux/missing
+build-aux/compile
+build-aux/test-driver
src/stamp-h1
libsecp256k1.pc
diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml
index 4e1e73c39f..2439529242 100644
--- a/src/secp256k1/.travis.yml
+++ b/src/secp256k1/.travis.yml
@@ -6,26 +6,30 @@ addons:
compiler:
- clang
- gcc
+cache:
+ directories:
+ - src/java/guava/
env:
global:
- - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no
+ - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no
+ - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
matrix:
- SCALAR=32bit RECOVERY=yes
- - SCALAR=32bit FIELD=32bit ECDH=yes
+ - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
- SCALAR=64bit
- FIELD=64bit RECOVERY=yes
- FIELD=64bit ENDOMORPHISM=yes
- - FIELD=64bit ENDOMORPHISM=yes ECDH=yes
+ - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
- FIELD=64bit ASM=x86_64
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
- - FIELD=32bit SCHNORR=yes
- FIELD=32bit ENDOMORPHISM=yes
- BIGNUM=no
- - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes
+ - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
- BIGNUM=no STATICPRECOMPUTATION=no
- BUILD=distcheck
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
- EXTRAFLAGS=CFLAGS=-O0
+ - BUILD=check-java ECDH=yes EXPERIMENTAL=yes
matrix:
fast_finish: true
include:
@@ -55,9 +59,11 @@ matrix:
packages:
- gcc-multilib
- libgmp-dev:i386
+before_install: mkdir -p `dirname $GUAVA_JAR`
+install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi
before_script: ./autogen.sh
script:
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
- - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
+ - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
os: linux
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index 7772a4e9d2..e5657f7f31 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -1,14 +1,22 @@
ACLOCAL_AMFLAGS = -I build-aux/m4
lib_LTLIBRARIES = libsecp256k1.la
+if USE_JNI
+JNI_LIB = libsecp256k1_jni.la
+noinst_LTLIBRARIES = $(JNI_LIB)
+else
+JNI_LIB =
+endif
include_HEADERS = include/secp256k1.h
noinst_HEADERS =
noinst_HEADERS += src/scalar.h
noinst_HEADERS += src/scalar_4x64.h
noinst_HEADERS += src/scalar_8x32.h
+noinst_HEADERS += src/scalar_low.h
noinst_HEADERS += src/scalar_impl.h
noinst_HEADERS += src/scalar_4x64_impl.h
noinst_HEADERS += src/scalar_8x32_impl.h
+noinst_HEADERS += src/scalar_low_impl.h
noinst_HEADERS += src/group.h
noinst_HEADERS += src/group_impl.h
noinst_HEADERS += src/num_gmp.h
@@ -32,6 +40,7 @@ noinst_HEADERS += src/field_5x52_impl.h
noinst_HEADERS += src/field_5x52_int128_impl.h
noinst_HEADERS += src/field_5x52_asm_impl.h
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
+noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/testrand.h
noinst_HEADERS += src/testrand_impl.h
@@ -45,33 +54,88 @@ noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
+if USE_EXTERNAL_ASM
+COMMON_LIB = libsecp256k1_common.la
+noinst_LTLIBRARIES = $(COMMON_LIB)
+else
+COMMON_LIB =
+endif
+
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsecp256k1.pc
+if USE_EXTERNAL_ASM
+if USE_ASM_ARM
+libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s
+endif
+endif
+
libsecp256k1_la_SOURCES = src/secp256k1.c
-libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
-libsecp256k1_la_LIBADD = $(SECP_LIBS)
+libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
+libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)
+libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c
+libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
noinst_PROGRAMS =
if USE_BENCHMARK
noinst_PROGRAMS += bench_verify bench_sign bench_internal
bench_verify_SOURCES = src/bench_verify.c
-bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_sign_SOURCES = src/bench_sign.c
-bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_internal_SOURCES = src/bench_internal.c
-bench_internal_LDADD = $(SECP_LIBS)
-bench_internal_CPPFLAGS = $(SECP_INCLUDES)
+bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
endif
+TESTS =
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
-tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
-tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS)
+tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
+tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
tests_LDFLAGS = -static
-TESTS = tests
+TESTS += tests
+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_LDADD = $(SECP_LIBS)
+exhaustive_tests_LDFLAGS = -static
+TESTS += exhaustive_tests
+endif
+
+JAVAROOT=src/java
+JAVAORG=org/bitcoin
+JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar
+CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA)
+JAVA_FILES= \
+ $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \
+ $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \
+ $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \
+ $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java
+
+if USE_JNI
+
+$(JAVA_GUAVA):
+ @echo Guava is missing. Fetch it via: \
+ wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@)
+ @false
+
+.stamp-java: $(JAVA_FILES)
+ @echo Compiling $^
+ $(AM_V_at)$(CLASSPATH_ENV) javac $^
+ @touch $@
+
+if USE_TESTS
+
+check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java
+ $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test
+
+endif
endif
if USE_ECMULT_STATIC_PRECOMPUTATION
@@ -93,19 +157,15 @@ $(bench_internal_OBJECTS): src/ecmult_static_context.h
src/ecmult_static_context.h: $(gen_context_BIN)
./$(gen_context_BIN)
-CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h
+CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java
endif
-EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h
+EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES)
if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include
endif
-if ENABLE_MODULE_SCHNORR
-include src/modules/schnorr/Makefile.am.include
-endif
-
if ENABLE_MODULE_RECOVERY
include src/modules/recovery/Makefile.am.include
endif
diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md
index 6095db4220..8cd344ea81 100644
--- a/src/secp256k1/README.md
+++ b/src/secp256k1/README.md
@@ -1,7 +1,7 @@
libsecp256k1
============
-[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1)
+[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)
Optimized C library for EC operations on curve secp256k1.
diff --git a/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
new file mode 100644
index 0000000000..1fc3627614
--- /dev/null
+++ b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
@@ -0,0 +1,140 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_JNI_INCLUDE_DIR
+#
+# DESCRIPTION
+#
+# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
+# programs using the JNI interface.
+#
+# JNI include directories are usually in the Java distribution. This is
+# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in
+# that order. When this macro completes, a list of directories is left in
+# the variable JNI_INCLUDE_DIRS.
+#
+# Example usage follows:
+#
+# AX_JNI_INCLUDE_DIR
+#
+# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
+# do
+# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
+# done
+#
+# If you want to force a specific compiler:
+#
+# - at the configure.in level, set JAVAC=yourcompiler before calling
+# AX_JNI_INCLUDE_DIR
+#
+# - at the configure level, setenv JAVAC
+#
+# Note: This macro can work with the autoconf M4 macros for Java programs.
+# This particular macro is not part of the original set of macros.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 10
+
+AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
+AC_DEFUN([AX_JNI_INCLUDE_DIR],[
+
+JNI_INCLUDE_DIRS=""
+
+if test "x$JAVA_HOME" != x; then
+ _JTOPDIR="$JAVA_HOME"
+else
+ if test "x$JAVAC" = x; then
+ JAVAC=javac
+ fi
+ AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
+ if test "x$_ACJNI_JAVAC" = xno; then
+ AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
+ fi
+ _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
+ _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
+fi
+
+case "$host_os" in
+ darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
+ _JINC="$_JTOPDIR/Headers";;
+ *) _JINC="$_JTOPDIR/include";;
+esac
+_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
+_AS_ECHO_LOG([_JINC=$_JINC])
+
+# On Mac OS X 10.6.4, jni.h is a symlink:
+# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
+# -> ../../CurrentJDK/Headers/jni.h.
+
+AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
+[
+if test -f "$_JINC/jni.h"; then
+ ac_cv_jni_header_path="$_JINC"
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
+else
+ _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
+ if test -f "$_JTOPDIR/include/jni.h"; then
+ ac_cv_jni_header_path="$_JTOPDIR/include"
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
+ else
+ ac_cv_jni_header_path=none
+ fi
+fi
+])
+
+
+
+# get the likely subdirectories for system specific java includes
+case "$host_os" in
+bsdi*) _JNI_INC_SUBDIRS="bsdos";;
+darwin*) _JNI_INC_SUBDIRS="darwin";;
+freebsd*) _JNI_INC_SUBDIRS="freebsd";;
+linux*) _JNI_INC_SUBDIRS="linux genunix";;
+osf*) _JNI_INC_SUBDIRS="alpha";;
+solaris*) _JNI_INC_SUBDIRS="solaris";;
+mingw*) _JNI_INC_SUBDIRS="win32";;
+cygwin*) _JNI_INC_SUBDIRS="win32";;
+*) _JNI_INC_SUBDIRS="genunix";;
+esac
+
+if test "x$ac_cv_jni_header_path" != "xnone"; then
+ # add any subdirectories that are present
+ for JINCSUBDIR in $_JNI_INC_SUBDIRS
+ do
+ if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
+ fi
+ done
+fi
+])
+
+# _ACJNI_FOLLOW_SYMLINKS <path>
+# Follows symbolic links on <path>,
+# finally setting variable _ACJNI_FOLLOWED
+# ----------------------------------------
+AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
+# find the include directory relative to the javac executable
+_cur="$1"
+while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
+ AC_MSG_CHECKING([symlink for $_cur])
+ _slink=`ls -ld "$_cur" | sed 's/.* -> //'`
+ case "$_slink" in
+ /*) _cur="$_slink";;
+ # 'X' avoids triggering unwanted echo options.
+ *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
+ esac
+ AC_MSG_RESULT([$_cur])
+done
+_ACJNI_FOLLOWED="$_cur"
+])# _ACJNI
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index d41bbb6487..b74acb8c13 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -3,13 +3,13 @@ AC_DEFUN([SECP_INT128_CHECK],[
has_int128=$ac_cv_type___int128
])
-dnl
+dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
AC_DEFUN([SECP_64BIT_ASM_CHECK],[
AC_MSG_CHECKING(for x86_64 assembly availability)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <stdint.h>]],[[
uint64_t a = 11, tmp;
- __asm__ __volatile__("movq $0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
+ __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
]])],[has_64bit_asm=yes],[has_64bit_asm=no])
AC_MSG_RESULT([$has_64bit_asm])
])
@@ -46,6 +46,10 @@ if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
EC_KEY_free(eckey);
+ ECDSA_SIG *sig_openssl;
+ sig_openssl = ECDSA_SIG_new();
+ (void)sig_openssl->r;
+ ECDSA_SIG_free(sig_openssl);
]])],[has_openssl_ec=yes],[has_openssl_ec=no])
AC_MSG_RESULT([$has_openssl_ec])
fi
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index 786d8dcfb9..ec50ffe3a2 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -29,6 +29,7 @@ AC_PROG_CC_C89
if test x"$ac_cv_prog_cc_c89" = x"no"; then
AC_MSG_ERROR([c89 compiler support required])
fi
+AM_PROG_AS
case $host_os in
*darwin*)
@@ -93,31 +94,46 @@ AC_ARG_ENABLE(tests,
[use_tests=$enableval],
[use_tests=yes])
+AC_ARG_ENABLE(openssl_tests,
+ AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]),
+ [enable_openssl_tests=$enableval],
+ [enable_openssl_tests=auto])
+
+AC_ARG_ENABLE(experimental,
+ AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]),
+ [use_experimental=$enableval],
+ [use_experimental=no])
+
+AC_ARG_ENABLE(exhaustive_tests,
+ AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]),
+ [use_exhaustive_tests=$enableval],
+ [use_exhaustive_tests=yes])
+
AC_ARG_ENABLE(endomorphism,
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
[use_endomorphism=$enableval],
[use_endomorphism=no])
-
+
AC_ARG_ENABLE(ecmult_static_precomputation,
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]),
[use_ecmult_static_precomputation=$enableval],
- [use_ecmult_static_precomputation=yes])
+ [use_ecmult_static_precomputation=auto])
AC_ARG_ENABLE(module_ecdh,
- AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (default is no)]),
+ AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]),
[enable_module_ecdh=$enableval],
[enable_module_ecdh=no])
-AC_ARG_ENABLE(module_schnorr,
- AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (default is no)]),
- [enable_module_schnorr=$enableval],
- [enable_module_schnorr=no])
-
AC_ARG_ENABLE(module_recovery,
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),
[enable_module_recovery=$enableval],
[enable_module_recovery=no])
+AC_ARG_ENABLE(jni,
+ AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
+ [use_jni=$enableval],
+ [use_jni=auto])
+
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
@@ -127,8 +143,8 @@ AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto])
-AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|no|auto]
-[Specify assembly optimizations to use. Default is auto])],[req_asm=$withval], [req_asm=auto])
+AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]
+[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto])
AC_CHECK_TYPES([__int128])
@@ -138,6 +154,34 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
[ AC_MSG_RESULT([no])
])
+if test x"$use_ecmult_static_precomputation" != x"no"; then
+ save_cross_compiling=$cross_compiling
+ cross_compiling=no
+ TEMP_CC="$CC"
+ CC="$CC_FOR_BUILD"
+ AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([], [return 0])],
+ [working_native_cc=yes],
+ [working_native_cc=no],[dnl])
+ CC="$TEMP_CC"
+ cross_compiling=$save_cross_compiling
+
+ if test x"$working_native_cc" = x"no"; then
+ set_precomp=no
+ if test x"$use_ecmult_static_precomputation" = x"yes"; then
+ AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
+ else
+ AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
+ fi
+ else
+ AC_MSG_RESULT([ok])
+ set_precomp=yes
+ fi
+else
+ set_precomp=no
+fi
+
if test x"$req_asm" = x"auto"; then
SECP_64BIT_ASM_CHECK
if test x"$has_64bit_asm" = x"yes"; then
@@ -155,6 +199,8 @@ else
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
fi
;;
+ arm)
+ ;;
no)
;;
*)
@@ -247,10 +293,15 @@ else
fi
# select assembly optimization
+use_external_asm=no
+
case $set_asm in
x86_64)
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
;;
+arm)
+ use_external_asm=yes
+ ;;
no)
;;
*)
@@ -305,16 +356,48 @@ esac
if test x"$use_tests" = x"yes"; then
SECP_OPENSSL_CHECK
if test x"$has_openssl_ec" = x"yes"; then
- AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
- SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
- SECP_TEST_LIBS="$CRYPTO_LIBS"
-
- case $host in
- *mingw*)
- SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
- ;;
- esac
+ if test x"$enable_openssl_tests" != x"no"; then
+ AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
+ SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
+ SECP_TEST_LIBS="$CRYPTO_LIBS"
+
+ case $host in
+ *mingw*)
+ SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
+ ;;
+ esac
+ fi
+ else
+ if test x"$enable_openssl_tests" = x"yes"; then
+ AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available])
+ fi
+ fi
+else
+ if test x"$enable_openssl_tests" = x"yes"; then
+ AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled])
+ fi
+fi
+if test x"$use_jni" != x"no"; then
+ AX_JNI_INCLUDE_DIR
+ have_jni_dependencies=yes
+ if test x"$enable_module_ecdh" = x"no"; then
+ have_jni_dependencies=no
+ fi
+ if test "x$JNI_INCLUDE_DIRS" = "x"; then
+ have_jni_dependencies=no
+ fi
+ if test "x$have_jni_dependencies" = "xno"; then
+ if test x"$use_jni" = x"yes"; then
+ AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.])
+ fi
+ AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
+ use_jni=no
+ else
+ use_jni=yes
+ for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
+ JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR"
+ done
fi
fi
@@ -327,7 +410,7 @@ if test x"$use_endomorphism" = x"yes"; then
AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
fi
-if test x"$use_ecmult_static_precomputation" = x"yes"; then
+if test x"$set_precomp" = x"yes"; then
AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table])
fi
@@ -335,38 +418,57 @@ if test x"$enable_module_ecdh" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
fi
-if test x"$enable_module_schnorr" = x"yes"; then
- AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module])
-fi
-
if test x"$enable_module_recovery" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
fi
AC_C_BIGENDIAN()
+if test x"$use_external_asm" = x"yes"; then
+ AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
+fi
+
+AC_MSG_NOTICE([Using static precomputation: $set_precomp])
AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
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 ECDH module: $enable_module_ecdh])
-
-AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
+AC_MSG_NOTICE([Using jni: $use_jni])
+
+if test x"$enable_experimental" = x"yes"; then
+ AC_MSG_NOTICE([******])
+ AC_MSG_NOTICE([WARNING: experimental build])
+ AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
+ AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
+ AC_MSG_NOTICE([******])
+else
+ if test x"$enable_module_ecdh" = x"yes"; then
+ AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
+ fi
+ if test x"$set_asm" = x"arm"; then
+ AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
+ fi
+fi
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
+AC_SUBST(JNI_INCLUDES)
AC_SUBST(SECP_INCLUDES)
AC_SUBST(SECP_LIBS)
AC_SUBST(SECP_TEST_LIBS)
AC_SUBST(SECP_TEST_INCLUDES)
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"])
-AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"])
+AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
-AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
+AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
+AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
+AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
dnl make sure nothing new is exported so that we don't break the cache
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index 7145dbcc54..f268e309d0 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -47,11 +47,8 @@ typedef struct secp256k1_context_struct secp256k1_context;
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* 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 or transmission, use
- * secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse.
- *
- * Furthermore, it is guaranteed that identical public keys (ignoring
- * compression) will have identical representation, so they can be memcmp'ed.
+ * If you need to convert to a format suitable for storage, transmission, or
+ * comparison, use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse.
*/
typedef struct {
unsigned char data[64];
@@ -62,12 +59,9 @@ typedef struct {
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* 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 or transmission, use
- * the secp256k1_ecdsa_signature_serialize_* and
+ * 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.
- *
- * Furthermore, it is guaranteed to identical signatures will have identical
- * representation, so they can be memcmp'ed.
*/
typedef struct {
unsigned char data[64];
diff --git a/src/secp256k1/include/secp256k1_schnorr.h b/src/secp256k1/include/secp256k1_schnorr.h
deleted file mode 100644
index dc32fec1ea..0000000000
--- a/src/secp256k1/include/secp256k1_schnorr.h
+++ /dev/null
@@ -1,173 +0,0 @@
-#ifndef _SECP256K1_SCHNORR_
-# define _SECP256K1_SCHNORR_
-
-# include "secp256k1.h"
-
-# ifdef __cplusplus
-extern "C" {
-# endif
-
-/** Create a signature using a custom EC-Schnorr-SHA256 construction. It
- * produces non-malleable 64-byte signatures which support public key recovery
- * batch validation, and multiparty signing.
- * Returns: 1: signature created
- * 0: the nonce generation function failed, or the private key was
- * invalid.
- * Args: ctx: pointer to a context object, initialized for signing
- * (cannot be NULL)
- * Out: sig64: pointer to a 64-byte array where the signature will be
- * placed (cannot be NULL)
- * In: msg32: the 32-byte message hash being signed (cannot be NULL)
- * seckey: pointer to a 32-byte secret key (cannot be NULL)
- * noncefp:pointer to a nonce generation function. If NULL,
- * secp256k1_nonce_function_default is used
- * ndata: pointer to arbitrary data used by the nonce generation
- * function (can be NULL)
- */
-SECP256K1_API int secp256k1_schnorr_sign(
- const secp256k1_context* ctx,
- unsigned char *sig64,
- const unsigned char *msg32,
- const unsigned char *seckey,
- secp256k1_nonce_function noncefp,
- const void *ndata
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-
-/** Verify a signature created by secp256k1_schnorr_sign.
- * Returns: 1: correct signature
- * 0: incorrect signature
- * Args: ctx: a secp256k1 context object, initialized for verification.
- * In: sig64: the 64-byte signature being verified (cannot be NULL)
- * msg32: the 32-byte message hash being verified (cannot be NULL)
- * pubkey: the public key to verify with (cannot be NULL)
- */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify(
- const secp256k1_context* ctx,
- const unsigned char *sig64,
- const unsigned char *msg32,
- const secp256k1_pubkey *pubkey
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-
-/** Recover an EC public key from a Schnorr signature created using
- * secp256k1_schnorr_sign.
- * Returns: 1: public key successfully recovered (which guarantees a correct
- * signature).
- * 0: otherwise.
- * Args: ctx: pointer to a context object, initialized for
- * verification (cannot be NULL)
- * Out: pubkey: pointer to a pubkey to set to the recovered public key
- * (cannot be NULL).
- * In: sig64: signature as 64 byte array (cannot be NULL)
- * msg32: the 32-byte message hash assumed to be signed (cannot
- * be NULL)
- */
-SECP256K1_API int secp256k1_schnorr_recover(
- const secp256k1_context* ctx,
- secp256k1_pubkey *pubkey,
- const unsigned char *sig64,
- const unsigned char *msg32
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-
-/** Generate a nonce pair deterministically for use with
- * secp256k1_schnorr_partial_sign.
- * Returns: 1: valid nonce pair was generated.
- * 0: otherwise (nonce generation function failed)
- * Args: ctx: pointer to a context object, initialized for signing
- * (cannot be NULL)
- * Out: pubnonce: public side of the nonce (cannot be NULL)
- * privnonce32: private side of the nonce (32 byte) (cannot be NULL)
- * In: msg32: the 32-byte message hash assumed to be signed (cannot
- * be NULL)
- * sec32: the 32-byte private key (cannot be NULL)
- * noncefp: pointer to a nonce generation function. If NULL,
- * secp256k1_nonce_function_default is used
- * noncedata: pointer to arbitrary data used by the nonce generation
- * function (can be NULL)
- *
- * Do not use the output as a private/public key pair for signing/validation.
- */
-SECP256K1_API int secp256k1_schnorr_generate_nonce_pair(
- const secp256k1_context* ctx,
- secp256k1_pubkey *pubnonce,
- unsigned char *privnonce32,
- const unsigned char *msg32,
- const unsigned char *sec32,
- secp256k1_nonce_function noncefp,
- const void* noncedata
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-
-/** Produce a partial Schnorr signature, which can be combined using
- * secp256k1_schnorr_partial_combine, to end up with a full signature that is
- * verifiable using secp256k1_schnorr_verify.
- * Returns: 1: signature created successfully.
- * 0: no valid signature exists with this combination of keys, nonces
- * and message (chance around 1 in 2^128)
- * -1: invalid private key, nonce, or public nonces.
- * Args: ctx: pointer to context object, initialized for signing (cannot
- * be NULL)
- * Out: sig64: pointer to 64-byte array to put partial signature in
- * In: msg32: pointer to 32-byte message to sign
- * sec32: pointer to 32-byte private key
- * pubnonce_others: pointer to pubkey containing the sum of the other's
- * nonces (see secp256k1_ec_pubkey_combine)
- * secnonce32: pointer to 32-byte array containing our nonce
- *
- * The intended procedure for creating a multiparty signature is:
- * - Each signer S[i] with private key x[i] and public key Q[i] runs
- * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of
- * private/public nonces.
- * - All signers communicate their public nonces to each other (revealing your
- * private nonce can lead to discovery of your private key, so it should be
- * considered secret).
- * - All signers combine all the public nonces they received (excluding their
- * own) using secp256k1_ec_pubkey_combine to obtain an
- * Rall[i] = sum(R[0..i-1,i+1..n]).
- * - All signers produce a partial signature using
- * secp256k1_schnorr_partial_sign, passing in their own private key x[i],
- * their own private nonce k[i], and the sum of the others' public nonces
- * Rall[i].
- * - All signers communicate their partial signatures to each other.
- * - Someone combines all partial signatures using
- * secp256k1_schnorr_partial_combine, to obtain a full signature.
- * - The resulting signature is validatable using secp256k1_schnorr_verify, with
- * public key equal to the result of secp256k1_ec_pubkey_combine of the
- * signers' public keys (sum(Q[0..n])).
- *
- * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine
- * function take their arguments in any order, and it is possible to
- * pre-combine several inputs already with one call, and add more inputs later
- * by calling the function again (they are commutative and associative).
- */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign(
- const secp256k1_context* ctx,
- unsigned char *sig64,
- const unsigned char *msg32,
- const unsigned char *sec32,
- const secp256k1_pubkey *pubnonce_others,
- const unsigned char *secnonce32
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
-
-/** Combine multiple Schnorr partial signatures.
- * Returns: 1: the passed signatures were successfully combined.
- * 0: the resulting signature is not valid (chance of 1 in 2^256)
- * -1: some inputs were invalid, or the signatures were not created
- * using the same set of nonces
- * Args: ctx: pointer to a context object
- * Out: sig64: pointer to a 64-byte array to place the combined signature
- * (cannot be NULL)
- * In: sig64sin: pointer to an array of n pointers to 64-byte input
- * signatures
- * n: the number of signatures to combine (at least 1)
- */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine(
- const secp256k1_context* ctx,
- unsigned char *sig64,
- const unsigned char * const * sig64sin,
- size_t n
-) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-
-# ifdef __cplusplus
-}
-# endif
-
-#endif
diff --git a/src/secp256k1/libsecp256k1.pc.in b/src/secp256k1/libsecp256k1.pc.in
index 1c72dd0003..a0d006f113 100644
--- a/src/secp256k1/libsecp256k1.pc.in
+++ b/src/secp256k1/libsecp256k1.pc.in
@@ -5,7 +5,7 @@ includedir=@includedir@
Name: libsecp256k1
Description: Optimized C library for EC operations on curve secp256k1
-URL: https://github.com/bitcoin/secp256k1
+URL: https://github.com/bitcoin-core/secp256k1
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs.private: @SECP_LIBS@
diff --git a/src/secp256k1/sage/group_prover.sage b/src/secp256k1/sage/group_prover.sage
new file mode 100644
index 0000000000..ab580c5b23
--- /dev/null
+++ b/src/secp256k1/sage/group_prover.sage
@@ -0,0 +1,322 @@
+# This code supports verifying group implementations which have branches
+# or conditional statements (like cmovs), by allowing each execution path
+# 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:
+# 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
+# is in the ideal with basis the zero expressions (in other words: when the
+# zero expressions imply that one of the nonzero expressions are zero).
+# * There is a list of laws that describe the intended behaviour, including
+# laws for addition and doubling. Each law is called with the symbolic point
+# coordinates as arguments, and returns:
+# - A constraint describing the assumptions under which it is applicable,
+# called "assumeLaw"
+# - 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:
+# - A constraint describing the assumptions this implementation requires
+# (such as Z1=1), called "assumeFormula"
+# - A constraint describing the assumptions this specific branch requires,
+# but which is by construction guaranteed to cover the entire space by
+# merging the results from all branches, called "assumeBranch"
+# - The result of the computation
+# * All combinations of laws with implementation branches are tried, and:
+# - If the combination of assumeLaw, assumeFormula, and assumeBranch results
+# in a conflict, it means this law does not apply to this branch, and it is
+# skipped.
+# - For others, we try to prove the require constraints hold, assuming the
+# information in assumeLaw + assumeFormula + assumeBranch, and if this does
+# not succeed, we fail.
+# + To prove an expression is zero, we check whether it belongs to the
+# ideal with the assumed zero expressions as basis. This test is exact.
+# + To prove an expression is nonzero, we check whether each of its
+# factors is contained in the set of nonzero assumptions' factors.
+# This test is not exact, so various combinations of original and
+# reduced expressions' factors are tried.
+# - If we succeed, we print out the assumptions from assumeFormula that
+# weren't implied by assumeLaw already. Those from assumeBranch are skipped,
+# as we assume that all constraints in it are complementary with each other.
+#
+# Based on the sage verification scripts used in the Explicit-Formulas Database
+# by Tanja Lange and others, see http://hyperelliptic.org/EFD
+
+class fastfrac:
+ """Fractions over rings."""
+
+ def __init__(self,R,top,bot=1):
+ """Construct a fractional, given a ring, a numerator, and denominator."""
+ self.R = R
+ if parent(top) == ZZ or parent(top) == R:
+ self.top = R(top)
+ self.bot = R(bot)
+ elif top.__class__ == fastfrac:
+ self.top = top.top
+ self.bot = top.bot * bot
+ else:
+ self.top = R(numerator(top))
+ self.bot = R(denominator(top)) * bot
+
+ def iszero(self,I):
+ """Return whether this fraction is zero given an ideal."""
+ return self.top in I and self.bot not in I
+
+ def reduce(self,assumeZero):
+ zero = self.R.ideal(map(numerator, assumeZero))
+ return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot))
+
+ def __add__(self,other):
+ """Add two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top + self.bot * other,self.bot)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot)
+ return NotImplemented
+
+ def __sub__(self,other):
+ """Subtract two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top - self.bot * other,self.bot)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot)
+ return NotImplemented
+
+ def __neg__(self):
+ """Return the negation of a fraction."""
+ return fastfrac(self.R,-self.top,self.bot)
+
+ def __mul__(self,other):
+ """Multiply two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top * other,self.bot)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.top,self.bot * other.bot)
+ return NotImplemented
+
+ def __rmul__(self,other):
+ """Multiply something else with a fraction."""
+ return self.__mul__(other)
+
+ def __div__(self,other):
+ """Divide two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top,self.bot * other)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.bot,self.bot * other.top)
+ return NotImplemented
+
+ def __pow__(self,other):
+ """Compute a power of a fraction."""
+ if parent(other) == ZZ:
+ if other < 0:
+ # Negative powers require flipping top and bottom
+ return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other))
+ else:
+ return fastfrac(self.R,self.top ^ other,self.bot ^ other)
+ return NotImplemented
+
+ def __str__(self):
+ return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))"
+ def __repr__(self):
+ return "%s" % self
+
+ def numerator(self):
+ return self.top
+
+class constraints:
+ """A set of constraints, consisting of zero and nonzero expressions.
+
+ Constraints can either be used to express knowledge or a requirement.
+
+ Both the fields zero and nonzero are maps from expressions to description
+ strings. The expressions that are the keys in zero are required to be zero,
+ and the expressions that are the keys in nonzero are required to be nonzero.
+
+ Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in
+ nonzero could be multiplied into a single key. This is often much less
+ efficient to work with though, so we keep them separate inside the
+ constraints. This allows higher-level code to do fast checks on the individual
+ nonzero elements, or combine them if needed for stronger checks.
+
+ We can't multiply the different zero elements, as it would suffice for one of
+ the factors to be zero, instead of all of them. Instead, the zero elements are
+ typically combined into an ideal first.
+ """
+
+ def __init__(self, **kwargs):
+ if 'zero' in kwargs:
+ self.zero = dict(kwargs['zero'])
+ else:
+ self.zero = dict()
+ if 'nonzero' in kwargs:
+ self.nonzero = dict(kwargs['nonzero'])
+ else:
+ self.nonzero = dict()
+
+ def negate(self):
+ return constraints(zero=self.nonzero, nonzero=self.zero)
+
+ def __add__(self, other):
+ zero = self.zero.copy()
+ zero.update(other.zero)
+ nonzero = self.nonzero.copy()
+ nonzero.update(other.nonzero)
+ return constraints(zero=zero, nonzero=nonzero)
+
+ def __str__(self):
+ return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero)
+
+ def __repr__(self):
+ return "%s" % self
+
+
+def conflicts(R, con):
+ """Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
+ zero = R.ideal(map(numerator, con.zero))
+ if 1 in zero:
+ return True
+ # First a cheap check whether any of the individual nonzero terms conflict on
+ # their own.
+ for nonzero in con.nonzero:
+ if nonzero.iszero(zero):
+ return True
+ # It can be the case that entries in the nonzero set do not individually
+ # conflict with the zero set, but their combination does. For example, knowing
+ # that either x or y is zero is equivalent to having x*y in the zero set.
+ # Having x or y individually in the nonzero set is not a conflict, but both
+ # simultaneously is, so that is the right thing to check for.
+ if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero):
+ return True
+ return False
+
+
+def get_nonzero_set(R, assume):
+ """Calculate a simple set of nonzero expressions"""
+ zero = R.ideal(map(numerator, assume.zero))
+ nonzero = set()
+ for nz in map(numerator, assume.nonzero):
+ for (f,n) in nz.factor():
+ nonzero.add(f)
+ rnz = zero.reduce(nz)
+ for (f,n) in rnz.factor():
+ nonzero.add(f)
+ return nonzero
+
+
+def prove_nonzero(R, exprs, assume):
+ """Check whether an expression is provably nonzero, given assumptions"""
+ zero = R.ideal(map(numerator, assume.zero))
+ nonzero = get_nonzero_set(R, assume)
+ expl = set()
+ ok = True
+ for expr in exprs:
+ if numerator(expr) in zero:
+ return (False, [exprs[expr]])
+ allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)
+ for (f, n) in allexprs.factor():
+ if f not in nonzero:
+ ok = False
+ if ok:
+ return (True, None)
+ ok = True
+ for (f, n) in zero.reduce(numerator(allexprs)).factor():
+ if f not in nonzero:
+ ok = False
+ if ok:
+ return (True, None)
+ ok = True
+ for expr in exprs:
+ for (f,n) in numerator(expr).factor():
+ if f not in nonzero:
+ ok = False
+ if ok:
+ return (True, None)
+ ok = True
+ for expr in exprs:
+ for (f,n) in zero.reduce(numerator(expr)).factor():
+ if f not in nonzero:
+ expl.add(exprs[expr])
+ if expl:
+ return (False, list(expl))
+ else:
+ return (True, None)
+
+
+def prove_zero(R, exprs, assume):
+ """Check whether all of the passed expressions are provably zero, given assumptions"""
+ r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
+ if not r:
+ return (False, map(lambda x: "Possibly zero denominator: %s" % x, e))
+ zero = R.ideal(map(numerator, assume.zero))
+ nonzero = prod(x for x in assume.nonzero)
+ expl = []
+ for expr in exprs:
+ if not expr.iszero(zero):
+ expl.append(exprs[expr])
+ if not expl:
+ return (True, None)
+ return (False, expl)
+
+
+def describe_extra(R, assume, assumeExtra):
+ """Describe what assumptions are added, given existing assumptions"""
+ zerox = assume.zero.copy()
+ zerox.update(assumeExtra.zero)
+ zero = R.ideal(map(numerator, assume.zero))
+ zeroextra = R.ideal(map(numerator, zerox))
+ nonzero = get_nonzero_set(R, assume)
+ ret = set()
+ # Iterate over the extra zero expressions
+ for base in assumeExtra.zero:
+ if base not in zero:
+ add = []
+ for (f, n) in numerator(base).factor():
+ if f not in nonzero:
+ add += ["%s" % f]
+ if add:
+ ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base])
+ # Iterate over the extra nonzero expressions
+ for nz in assumeExtra.nonzero:
+ nzr = zeroextra.reduce(numerator(nz))
+ if nzr not in zeroextra:
+ for (f,n) in nzr.factor():
+ if zeroextra.reduce(f) not in nonzero:
+ ret.add("%s != 0" % zeroextra.reduce(f))
+ return ", ".join(x for x in ret)
+
+
+def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require):
+ """Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions"""
+ assume = assumeLaw + assumeAssert + assumeBranch
+
+ if conflicts(R, assume):
+ # This formula does not apply
+ return None
+
+ describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)
+
+ ok, msg = prove_zero(R, require.zero, assume)
+ if not ok:
+ return "FAIL, %s fails (assuming %s)" % (str(msg), describe)
+
+ res, expl = prove_nonzero(R, require.nonzero, assume)
+ if not res:
+ return "FAIL, %s fails (assuming %s)" % (str(expl), describe)
+
+ if describe != "":
+ return "OK (assuming %s)" % describe
+ else:
+ return "OK"
+
+
+def concrete_verify(c):
+ for k in c.zero:
+ if k != 0:
+ return (False, c.zero[k])
+ for k in c.nonzero:
+ if k == 0:
+ return (False, c.nonzero[k])
+ return (True, None)
diff --git a/src/secp256k1/sage/secp256k1.sage b/src/secp256k1/sage/secp256k1.sage
new file mode 100644
index 0000000000..a97e732f7f
--- /dev/null
+++ b/src/secp256k1/sage/secp256k1.sage
@@ -0,0 +1,306 @@
+# Test libsecp256k1' group operation implementations using prover.sage
+
+import sys
+
+load("group_prover.sage")
+load("weierstrass_prover.sage")
+
+def formula_secp256k1_gej_double_var(a):
+ """libsecp256k1's secp256k1_gej_double_var, used by various addition functions"""
+ rz = a.Z * a.Y
+ rz = rz * 2
+ t1 = a.X^2
+ t1 = t1 * 3
+ t2 = t1^2
+ t3 = a.Y^2
+ t3 = t3 * 2
+ t4 = t3^2
+ t4 = t4 * 2
+ t3 = t3 * a.X
+ rx = t3
+ rx = rx * 4
+ rx = -rx
+ rx = rx + t2
+ t2 = -t2
+ t3 = t3 * 6
+ t3 = t3 + t2
+ ry = t1 * t3
+ t2 = -t4
+ ry = ry + t2
+ return jacobianpoint(rx, ry, rz)
+
+def formula_secp256k1_gej_add_var(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_var"""
+ if branch == 0:
+ return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b)
+ if branch == 1:
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
+ z22 = b.Z^2
+ z12 = a.Z^2
+ u1 = a.X * z22
+ u2 = b.X * z12
+ s1 = a.Y * z22
+ s1 = s1 * b.Z
+ s2 = b.Y * z12
+ s2 = s2 * a.Z
+ h = -u1
+ h = h + u2
+ i = -s1
+ i = i + s2
+ if branch == 2:
+ r = formula_secp256k1_gej_double_var(a)
+ return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r)
+ if branch == 3:
+ return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity())
+ i2 = i^2
+ h2 = h^2
+ h3 = h2 * h
+ h = h * b.Z
+ rz = a.Z * h
+ t = u1 * h2
+ rx = t
+ rx = rx * 2
+ rx = rx + h3
+ rx = -rx
+ rx = rx + i2
+ ry = -rx
+ ry = ry + t
+ ry = ry * i
+ h3 = h3 * s1
+ h3 = -h3
+ ry = ry + h3
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_ge_var(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1"""
+ if branch == 0:
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b)
+ if branch == 1:
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
+ z12 = a.Z^2
+ u1 = a.X
+ u2 = b.X * z12
+ s1 = a.Y
+ s2 = b.Y * z12
+ s2 = s2 * a.Z
+ h = -u1
+ h = h + u2
+ i = -s1
+ i = i + s2
+ if (branch == 2):
+ r = formula_secp256k1_gej_double_var(a)
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)
+ if (branch == 3):
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())
+ i2 = i^2
+ h2 = h^2
+ h3 = h * h2
+ rz = a.Z * h
+ t = u1 * h2
+ rx = t
+ rx = rx * 2
+ rx = rx + h3
+ rx = -rx
+ rx = rx + i2
+ ry = -rx
+ ry = ry + t
+ ry = ry * i
+ h3 = h3 * s1
+ h3 = -h3
+ ry = ry + h3
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_zinv_var(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_zinv_var"""
+ bzinv = b.Z^(-1)
+ if branch == 0:
+ return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a)
+ if branch == 1:
+ bzinv2 = bzinv^2
+ bzinv3 = bzinv2 * bzinv
+ rx = b.X * bzinv2
+ ry = b.Y * bzinv3
+ rz = 1
+ return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz))
+ azz = a.Z * bzinv
+ z12 = azz^2
+ u1 = a.X
+ u2 = b.X * z12
+ s1 = a.Y
+ s2 = b.Y * z12
+ s2 = s2 * azz
+ h = -u1
+ h = h + u2
+ i = -s1
+ i = i + s2
+ if branch == 2:
+ r = formula_secp256k1_gej_double_var(a)
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)
+ if branch == 3:
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())
+ i2 = i^2
+ h2 = h^2
+ h3 = h * h2
+ rz = a.Z
+ rz = rz * h
+ t = u1 * h2
+ rx = t
+ rx = rx * 2
+ rx = rx + h3
+ rx = -rx
+ rx = rx + i2
+ ry = -rx
+ ry = ry + t
+ ry = ry * i
+ h3 = h3 * s1
+ h3 = -h3
+ ry = ry + h3
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_ge(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_ge"""
+ zeroes = {}
+ nonzeroes = {}
+ a_infinity = False
+ if (branch & 4) != 0:
+ nonzeroes.update({a.Infinity : 'a_infinite'})
+ a_infinity = True
+ else:
+ zeroes.update({a.Infinity : 'a_finite'})
+ zz = a.Z^2
+ u1 = a.X
+ u2 = b.X * zz
+ s1 = a.Y
+ s2 = b.Y * zz
+ s2 = s2 * a.Z
+ t = u1
+ t = t + u2
+ m = s1
+ m = m + s2
+ rr = t^2
+ m_alt = -u2
+ tt = u1 * m_alt
+ rr = rr + tt
+ degenerate = (branch & 3) == 3
+ if (branch & 1) != 0:
+ zeroes.update({m : 'm_zero'})
+ else:
+ nonzeroes.update({m : 'm_nonzero'})
+ if (branch & 2) != 0:
+ zeroes.update({rr : 'rr_zero'})
+ else:
+ nonzeroes.update({rr : 'rr_nonzero'})
+ rr_alt = s1
+ rr_alt = rr_alt * 2
+ m_alt = m_alt + u1
+ if not degenerate:
+ rr_alt = rr
+ m_alt = m
+ n = m_alt^2
+ q = n * t
+ n = n^2
+ if degenerate:
+ n = m
+ t = rr_alt^2
+ rz = a.Z * m_alt
+ infinity = False
+ if (branch & 8) != 0:
+ if not a_infinity:
+ infinity = True
+ zeroes.update({rz : 'r.z=0'})
+ else:
+ nonzeroes.update({rz : 'r.z!=0'})
+ rz = rz * 2
+ q = -q
+ t = t + q
+ rx = t
+ t = t * 2
+ t = t + q
+ t = t * rr_alt
+ t = t + n
+ ry = -t
+ rx = rx * 4
+ ry = ry * 4
+ if a_infinity:
+ rx = b.X
+ ry = b.Y
+ rz = 1
+ if infinity:
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity())
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_ge_old(branch, a, b):
+ """libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx"""
+ a_infinity = (branch & 1) != 0
+ zero = {}
+ nonzero = {}
+ if a_infinity:
+ nonzero.update({a.Infinity : 'a_infinite'})
+ else:
+ zero.update({a.Infinity : 'a_finite'})
+ zz = a.Z^2
+ u1 = a.X
+ u2 = b.X * zz
+ s1 = a.Y
+ s2 = b.Y * zz
+ s2 = s2 * a.Z
+ z = a.Z
+ t = u1
+ t = t + u2
+ m = s1
+ m = m + s2
+ n = m^2
+ q = n * t
+ n = n^2
+ rr = t^2
+ t = u1 * u2
+ t = -t
+ rr = rr + t
+ t = rr^2
+ rz = m * z
+ infinity = False
+ if (branch & 2) != 0:
+ if not a_infinity:
+ infinity = True
+ else:
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity())
+ zero.update({rz : 'r.z=0'})
+ else:
+ nonzero.update({rz : 'r.z!=0'})
+ rz = rz * (0 if a_infinity else 2)
+ rx = t
+ q = -q
+ rx = rx + q
+ q = q * 3
+ t = t * 2
+ t = t + q
+ t = t * rr
+ t = t + n
+ ry = -t
+ rx = rx * (0 if a_infinity else 4)
+ ry = ry * (0 if a_infinity else 4)
+ t = b.X
+ t = t * (1 if a_infinity else 0)
+ rx = rx + t
+ t = b.Y
+ t = t * (1 if a_infinity else 0)
+ ry = ry + t
+ t = (1 if a_infinity else 0)
+ rz = rz + t
+ if infinity:
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity())
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz))
+
+if __name__ == "__main__":
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)
+
+ if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)
diff --git a/src/secp256k1/sage/weierstrass_prover.sage b/src/secp256k1/sage/weierstrass_prover.sage
new file mode 100644
index 0000000000..03ef2ec901
--- /dev/null
+++ b/src/secp256k1/sage/weierstrass_prover.sage
@@ -0,0 +1,264 @@
+# Prover implementation for Weierstrass curves of the form
+# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws
+# operating on affine and Jacobian coordinates, including the point at infinity
+# represented by a 4th variable in coordinates.
+
+load("group_prover.sage")
+
+
+class affinepoint:
+ def __init__(self, x, y, infinity=0):
+ self.x = x
+ self.y = y
+ self.infinity = infinity
+ def __str__(self):
+ return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity)
+
+
+class jacobianpoint:
+ def __init__(self, x, y, z, infinity=0):
+ self.X = x
+ self.Y = y
+ self.Z = z
+ self.Infinity = infinity
+ def __str__(self):
+ return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity)
+
+
+def point_at_infinity():
+ return jacobianpoint(1, 1, 1, 1)
+
+
+def negate(p):
+ if p.__class__ == affinepoint:
+ return affinepoint(p.x, -p.y)
+ if p.__class__ == jacobianpoint:
+ return jacobianpoint(p.X, -p.Y, p.Z)
+ assert(False)
+
+
+def on_weierstrass_curve(A, B, p):
+ """Return a set of zero-expressions for an affine point to be on the curve"""
+ return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'})
+
+
+def tangential_to_weierstrass_curve(A, B, p12, p3):
+ """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)"""
+ return constraints(zero={
+ (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve'
+ })
+
+
+def colinear(p1, p2, p3):
+ """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear"""
+ return constraints(zero={
+ (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1',
+ (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2',
+ (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3'
+ })
+
+
+def good_affine_point(p):
+ return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'})
+
+
+def good_jacobian_point(p):
+ return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'})
+
+
+def good_point(p):
+ return constraints(nonzero={p.Z^6 : 'nonzero_X'})
+
+
+def finite(p, *affine_fns):
+ con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'})
+ if p.Z != 0:
+ return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con)
+ else:
+ return con
+
+def infinite(p):
+ return constraints(nonzero={p.Infinity : 'infinite_point'})
+
+
+def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC):
+ """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions"""
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ on_weierstrass_curve(A, B, pb) +
+ finite(pA) +
+ finite(pB) +
+ constraints(nonzero={pa.x - pb.x : 'different_x'}))
+ require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
+ colinear(pa, pb, negate(pc))))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC):
+ """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions"""
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ on_weierstrass_curve(A, B, pb) +
+ finite(pA) +
+ finite(pB) +
+ constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'}))
+ require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
+ tangential_to_weierstrass_curve(A, B, pa, negate(pc))))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ on_weierstrass_curve(A, B, pb) +
+ finite(pA) +
+ finite(pB) +
+ constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'}))
+ require = infinite(pC)
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pb) +
+ infinite(pA) +
+ finite(pB))
+ require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'}))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ infinite(pB) +
+ finite(pA))
+ require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'}))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ infinite(pA) +
+ infinite(pB))
+ require = infinite(pC)
+ return (assumeLaw, require)
+
+
+laws_jacobian_weierstrass = {
+ 'add': law_jacobian_weierstrass_add,
+ 'double': law_jacobian_weierstrass_double,
+ 'add_opposite': law_jacobian_weierstrass_add_opposites,
+ 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a,
+ 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b,
+ 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab
+}
+
+
+def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
+ """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field"""
+ F = Integers(p)
+ print "Formula %s on Z%i:" % (name, p)
+ points = []
+ for x in xrange(0, p):
+ for y in xrange(0, p):
+ point = affinepoint(F(x), F(y))
+ r, e = concrete_verify(on_weierstrass_curve(A, B, point))
+ if r:
+ points.append(point)
+
+ for za in xrange(1, p):
+ for zb in xrange(1, p):
+ for pa in points:
+ for pb in points:
+ for ia in xrange(2):
+ for ib in xrange(2):
+ pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia)
+ pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib)
+ for branch in xrange(0, branches):
+ assumeAssert, assumeBranch, pC = formula(branch, pA, pB)
+ pC.X = F(pC.X)
+ pC.Y = F(pC.Y)
+ pC.Z = F(pC.Z)
+ pC.Infinity = F(pC.Infinity)
+ r, e = concrete_verify(assumeAssert + assumeBranch)
+ if r:
+ match = False
+ for key in laws_jacobian_weierstrass:
+ assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC)
+ r, e = concrete_verify(assumeLaw)
+ if r:
+ if match:
+ print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)
+ else:
+ match = True
+ r, e = concrete_verify(require)
+ if not r:
+ print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e)
+ print
+
+
+def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
+ assumeLaw, require = f(A, B, pa, pb, pA, pB, pC)
+ return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require)
+
+def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
+ """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically"""
+ R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')
+ lift = lambda x: fastfrac(R,x)
+ ax = lift(ax)
+ ay = lift(ay)
+ Az = lift(Az)
+ bx = lift(bx)
+ by = lift(by)
+ Bz = lift(Bz)
+ Ai = lift(Ai)
+ Bi = lift(Bi)
+
+ pa = affinepoint(ax, ay, Ai)
+ pb = affinepoint(bx, by, Bi)
+ pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai)
+ pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi)
+
+ res = {}
+
+ for key in laws_jacobian_weierstrass:
+ res[key] = []
+
+ print ("Formula " + name + ":")
+ count = 0
+ for branch in xrange(branches):
+ assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
+ pC.X = lift(pC.X)
+ pC.Y = lift(pC.Y)
+ pC.Z = lift(pC.Z)
+ pC.Infinity = lift(pC.Infinity)
+
+ for key in laws_jacobian_weierstrass:
+ res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
+
+ for key in res:
+ print " %s:" % key
+ val = res[key]
+ for x in val:
+ if x[0] is not None:
+ print " branch %i: %s" % (x[1], x[0])
+
+ print
diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s
new file mode 100644
index 0000000000..5df561f2fc
--- /dev/null
+++ b/src/secp256k1/src/asm/field_10x26_arm.s
@@ -0,0 +1,919 @@
+@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm:
+/**********************************************************************
+ * Copyright (c) 2014 Wladimir J. van der Laan *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+/*
+ARM implementation of field_10x26 inner loops.
+
+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
+
+*/
+
+ .syntax unified
+ .arch armv7-a
+ @ eabi attributes - see readelf -A
+ .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes
+ .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no
+ .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 34, 1 @ Tag_CPU_unaligned_access = v6
+ .text
+
+ @ Field constants
+ .set field_R0, 0x3d10
+ .set field_R1, 0x400
+ .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff
+
+ .align 2
+ .global secp256k1_fe_mul_inner
+ .type secp256k1_fe_mul_inner, %function
+ @ Arguments:
+ @ r0 r Restrict: can overlap with a, not with b
+ @ r1 a
+ @ r2 b
+ @ Stack (total 4+10*4 = 44)
+ @ sp + #0 saved 'r' pointer
+ @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9
+secp256k1_fe_mul_inner:
+ stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}
+ sub sp, sp, #48 @ frame=44 + alignment
+ str r0, [sp, #0] @ save result address, we need it only at the end
+
+ /******************************************
+ * Main computation code.
+ ******************************************
+
+ Allocation:
+ r0,r14,r7,r8 scratch
+ r1 a (pointer)
+ r2 b (pointer)
+ r3:r4 c
+ r5:r6 d
+ r11:r12 c'
+ r9:r10 d'
+
+ Note: do not write to r[] here, it may overlap with a[]
+ */
+
+ /* A - interleaved with B */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #9*4] @ b[9]
+ ldr r0, [r1, #1*4] @ a[1]
+ umull r5, r6, r7, r8 @ d = a[0] * b[9]
+ ldr r14, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r8 @ d' = a[1] * b[9]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r5, r6, r0, r14 @ d += a[1] * b[8]
+ ldr r8, [r2, #7*4] @ b[7]
+ umlal r9, r10, r7, r14 @ d' += a[2] * b[8]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r5, r6, r7, r8 @ d += a[2] * b[7]
+ ldr r14, [r2, #6*4] @ b[6]
+ umlal r9, r10, r0, r8 @ d' += a[3] * b[7]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r5, r6, r0, r14 @ d += a[3] * b[6]
+ ldr r8, [r2, #5*4] @ b[5]
+ umlal r9, r10, r7, r14 @ d' += a[4] * b[6]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r5, r6, r7, r8 @ d += a[4] * b[5]
+ ldr r14, [r2, #4*4] @ b[4]
+ umlal r9, r10, r0, r8 @ d' += a[5] * b[5]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r5, r6, r0, r14 @ d += a[5] * b[4]
+ ldr r8, [r2, #3*4] @ b[3]
+ umlal r9, r10, r7, r14 @ d' += a[6] * b[4]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r5, r6, r7, r8 @ d += a[6] * b[3]
+ ldr r14, [r2, #2*4] @ b[2]
+ umlal r9, r10, r0, r8 @ d' += a[7] * b[3]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r14 @ d += a[7] * b[2]
+ ldr r8, [r2, #1*4] @ b[1]
+ umlal r9, r10, r7, r14 @ d' += a[8] * b[2]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r8 @ d += a[8] * b[1]
+ ldr r14, [r2, #0*4] @ b[0]
+ umlal r9, r10, r0, r8 @ d' += a[9] * b[1]
+ ldr r7, [r1, #0*4] @ a[0]
+ umlal r5, r6, r0, r14 @ d += a[9] * b[0]
+ @ r7,r14 used in B
+
+ bic r0, r5, field_not_M @ t9 = d & M
+ str r0, [sp, #4 + 4*9]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ /* B */
+ umull r3, r4, r7, r14 @ c = a[0] * b[0]
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u0 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u0 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t0 = c & M
+ str r14, [sp, #4 + 0*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u0 * R1
+ umlal r3, r4, r0, r14
+
+ /* C - interleaved with D */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #2*4] @ b[2]
+ ldr r14, [r2, #1*4] @ b[1]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[2]
+ ldr r0, [r1, #1*4] @ a[1]
+ umlal r3, r4, r7, r14 @ c += a[0] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r11, r12, r0, r14 @ c' += a[1] * b[1]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r8 @ c += a[1] * b[0]
+ ldr r14, [r2, #9*4] @ b[9]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[0]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r5, r6, r7, r14 @ d += a[2] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r14 @ d' = a[3] * b[9]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r5, r6, r0, r8 @ d += a[3] * b[8]
+ ldr r14, [r2, #7*4] @ b[7]
+ umlal r9, r10, r7, r8 @ d' += a[4] * b[8]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r5, r6, r7, r14 @ d += a[4] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r9, r10, r0, r14 @ d' += a[5] * b[7]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r5, r6, r0, r8 @ d += a[5] * b[6]
+ ldr r14, [r2, #5*4] @ b[5]
+ umlal r9, r10, r7, r8 @ d' += a[6] * b[6]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r5, r6, r7, r14 @ d += a[6] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r9, r10, r0, r14 @ d' += a[7] * b[5]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r8 @ d += a[7] * b[4]
+ ldr r14, [r2, #3*4] @ b[3]
+ umlal r9, r10, r7, r8 @ d' += a[8] * b[4]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r14 @ d += a[8] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r9, r10, r0, r14 @ d' += a[9] * b[3]
+ umlal r5, r6, r0, r8 @ d += a[9] * b[2]
+
+ bic r0, r5, field_not_M @ u1 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u1 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t1 = c & M
+ str r14, [sp, #4 + 1*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u1 * R1
+ umlal r3, r4, r0, r14
+
+ /* D */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u2 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u2 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t2 = c & M
+ str r14, [sp, #4 + 2*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u2 * R1
+ umlal r3, r4, r0, r14
+
+ /* E - interleaved with F */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #4*4] @ b[4]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[4]
+ ldr r8, [r2, #3*4] @ b[3]
+ umlal r3, r4, r7, r8 @ c += a[0] * b[3]
+ ldr r7, [r1, #1*4] @ a[1]
+ umlal r11, r12, r7, r8 @ c' += a[1] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r3, r4, r7, r8 @ c += a[1] * b[2]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[2]
+ ldr r8, [r2, #1*4] @ b[1]
+ umlal r3, r4, r7, r8 @ c += a[2] * b[1]
+ ldr r7, [r1, #3*4] @ a[3]
+ umlal r11, r12, r7, r8 @ c' += a[3] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r3, r4, r7, r8 @ c += a[3] * b[0]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r11, r12, r7, r8 @ c' += a[4] * b[0]
+ ldr r8, [r2, #9*4] @ b[9]
+ umlal r5, r6, r7, r8 @ d += a[4] * b[9]
+ ldr r7, [r1, #5*4] @ a[5]
+ umull r9, r10, r7, r8 @ d' = a[5] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umlal r5, r6, r7, r8 @ d += a[5] * b[8]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r9, r10, r7, r8 @ d' += a[6] * b[8]
+ ldr r8, [r2, #7*4] @ b[7]
+ umlal r5, r6, r7, r8 @ d += a[6] * b[7]
+ ldr r7, [r1, #7*4] @ a[7]
+ umlal r9, r10, r7, r8 @ d' += a[7] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r5, r6, r7, r8 @ d += a[7] * b[6]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r9, r10, r7, r8 @ d' += a[8] * b[6]
+ ldr r8, [r2, #5*4] @ b[5]
+ umlal r5, r6, r7, r8 @ d += a[8] * b[5]
+ ldr r7, [r1, #9*4] @ a[9]
+ umlal r9, r10, r7, r8 @ d' += a[9] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r5, r6, r7, r8 @ d += a[9] * b[4]
+
+ bic r0, r5, field_not_M @ u3 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u3 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t3 = c & M
+ str r14, [sp, #4 + 3*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u3 * R1
+ umlal r3, r4, r0, r14
+
+ /* F */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u4 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u4 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t4 = c & M
+ str r14, [sp, #4 + 4*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u4 * R1
+ umlal r3, r4, r0, r14
+
+ /* G - interleaved with H */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #6*4] @ b[6]
+ ldr r14, [r2, #5*4] @ b[5]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[6]
+ ldr r0, [r1, #1*4] @ a[1]
+ umlal r3, r4, r7, r14 @ c += a[0] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r11, r12, r0, r14 @ c' += a[1] * b[5]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r8 @ c += a[1] * b[4]
+ ldr r14, [r2, #3*4] @ b[3]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[4]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r3, r4, r7, r14 @ c += a[2] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r11, r12, r0, r14 @ c' += a[3] * b[3]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r3, r4, r0, r8 @ c += a[3] * b[2]
+ ldr r14, [r2, #1*4] @ b[1]
+ umlal r11, r12, r7, r8 @ c' += a[4] * b[2]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r3, r4, r7, r14 @ c += a[4] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r11, r12, r0, r14 @ c' += a[5] * b[1]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r3, r4, r0, r8 @ c += a[5] * b[0]
+ ldr r14, [r2, #9*4] @ b[9]
+ umlal r11, r12, r7, r8 @ c' += a[6] * b[0]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r5, r6, r7, r14 @ d += a[6] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r14 @ d' = a[7] * b[9]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r8 @ d += a[7] * b[8]
+ ldr r14, [r2, #7*4] @ b[7]
+ umlal r9, r10, r7, r8 @ d' += a[8] * b[8]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r14 @ d += a[8] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r9, r10, r0, r14 @ d' += a[9] * b[7]
+ umlal r5, r6, r0, r8 @ d += a[9] * b[6]
+
+ bic r0, r5, field_not_M @ u5 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u5 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t5 = c & M
+ str r14, [sp, #4 + 5*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u5 * R1
+ umlal r3, r4, r0, r14
+
+ /* H */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u6 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u6 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t6 = c & M
+ str r14, [sp, #4 + 6*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u6 * R1
+ umlal r3, r4, r0, r14
+
+ /* I - interleaved with J */
+ ldr r8, [r2, #8*4] @ b[8]
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r14, [r2, #7*4] @ b[7]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[8]
+ ldr r0, [r1, #1*4] @ a[1]
+ umlal r3, r4, r7, r14 @ c += a[0] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r11, r12, r0, r14 @ c' += a[1] * b[7]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r8 @ c += a[1] * b[6]
+ ldr r14, [r2, #5*4] @ b[5]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[6]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r3, r4, r7, r14 @ c += a[2] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r11, r12, r0, r14 @ c' += a[3] * b[5]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r3, r4, r0, r8 @ c += a[3] * b[4]
+ ldr r14, [r2, #3*4] @ b[3]
+ umlal r11, r12, r7, r8 @ c' += a[4] * b[4]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r3, r4, r7, r14 @ c += a[4] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r11, r12, r0, r14 @ c' += a[5] * b[3]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r3, r4, r0, r8 @ c += a[5] * b[2]
+ ldr r14, [r2, #1*4] @ b[1]
+ umlal r11, r12, r7, r8 @ c' += a[6] * b[2]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r3, r4, r7, r14 @ c += a[6] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r11, r12, r0, r14 @ c' += a[7] * b[1]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r3, r4, r0, r8 @ c += a[7] * b[0]
+ ldr r14, [r2, #9*4] @ b[9]
+ umlal r11, r12, r7, r8 @ c' += a[8] * b[0]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r14 @ d += a[8] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r14 @ d' = a[9] * b[9]
+ umlal r5, r6, r0, r8 @ d += a[9] * b[8]
+
+ bic r0, r5, field_not_M @ u7 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u7 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t7 = c & M
+ str r14, [sp, #4 + 7*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u7 * R1
+ umlal r3, r4, r0, r14
+
+ /* J */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u8 = d & M
+ str r0, [sp, #4 + 8*4]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u8 * R0
+ umlal r3, r4, r0, r14
+
+ /******************************************
+ * compute and write back result
+ ******************************************
+ Allocation:
+ r0 r
+ r3:r4 c
+ r5:r6 d
+ r7 t0
+ r8 t1
+ r9 t2
+ r11 u8
+ r12 t9
+ r1,r2,r10,r14 scratch
+
+ Note: do not read from a[] after here, it may overlap with r[]
+ */
+ ldr r0, [sp, #0]
+ add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
+ ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
+ add r1, r0, #3*4
+ stmia r1, {r2,r7,r8,r9,r10}
+
+ bic r2, r3, field_not_M @ r[8] = c & M
+ str r2, [r0, #8*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u8 * R1
+ umlal r3, r4, r11, r14
+ movw r14, field_R0 @ c += d * R0
+ umlal r3, r4, r5, r14
+ adds r3, r3, r12 @ c += t9
+ adc r4, r4, #0
+
+ add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
+ ldmia r1, {r7,r8,r9}
+
+ ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
+ str r2, [r0, #9*4]
+ mov r3, r3, lsr #22 @ c >>= 22
+ orr r3, r3, r4, asl #10
+ mov r4, r4, lsr #22
+ movw r14, field_R1 << 4 @ c += d * (R1 << 4)
+ umlal r3, r4, r5, r14
+
+ movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
+ umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
+ adds r5, r5, r7 @ d.lo += t0
+ mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
+ adc r6, r6, 0 @ d.hi += carry
+
+ bic r2, r5, field_not_M @ r[0] = d & M
+ str r2, [r0, #0*4]
+
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
+ umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
+ adds r5, r5, r8 @ d.lo += t1
+ adc r6, r6, #0 @ d.hi += carry
+ adds r5, r5, r1 @ d.lo += tmp.lo
+ mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
+ adc r6, r6, r2 @ d.hi += carry + tmp.hi
+
+ bic r2, r5, field_not_M @ r[1] = d & M
+ str r2, [r0, #1*4]
+ mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
+ orr r5, r5, r6, asl #6
+
+ add r5, r5, r9 @ d += t2
+ str r5, [r0, #2*4] @ r[2] = d
+
+ add sp, sp, #48
+ ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
+ .size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner
+
+ .align 2
+ .global secp256k1_fe_sqr_inner
+ .type secp256k1_fe_sqr_inner, %function
+ @ Arguments:
+ @ r0 r Can overlap with a
+ @ r1 a
+ @ Stack (total 4+10*4 = 44)
+ @ sp + #0 saved 'r' pointer
+ @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9
+secp256k1_fe_sqr_inner:
+ stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}
+ sub sp, sp, #48 @ frame=44 + alignment
+ str r0, [sp, #0] @ save result address, we need it only at the end
+ /******************************************
+ * Main computation code.
+ ******************************************
+
+ Allocation:
+ r0,r14,r2,r7,r8 scratch
+ r1 a (pointer)
+ r3:r4 c
+ r5:r6 d
+ r11:r12 c'
+ r9:r10 d'
+
+ Note: do not write to r[] here, it may overlap with a[]
+ */
+ /* A interleaved with B */
+ ldr r0, [r1, #1*4] @ a[1]*2
+ ldr r7, [r1, #0*4] @ a[0]
+ mov r0, r0, asl #1
+ ldr r14, [r1, #9*4] @ a[9]
+ umull r3, r4, r7, r7 @ c = a[0] * a[0]
+ ldr r8, [r1, #8*4] @ a[8]
+ mov r7, r7, asl #1
+ umull r5, r6, r7, r14 @ d = a[0]*2 * a[9]
+ ldr r7, [r1, #2*4] @ a[2]*2
+ umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9]
+ ldr r14, [r1, #7*4] @ a[7]
+ umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8]
+ mov r7, r7, asl #1
+ ldr r0, [r1, #3*4] @ a[3]*2
+ umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8]
+ ldr r8, [r1, #6*4] @ a[6]
+ umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7]
+ mov r0, r0, asl #1
+ ldr r7, [r1, #4*4] @ a[4]*2
+ umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7]
+ ldr r14, [r1, #5*4] @ a[5]
+ mov r7, r7, asl #1
+ umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6]
+ umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6]
+ umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5]
+ umlal r9, r10, r14, r14 @ d' += a[5] * a[5]
+
+ bic r0, r5, field_not_M @ t9 = d & M
+ str r0, [sp, #4 + 9*4]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ /* B */
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u0 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u0 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t0 = c & M
+ str r14, [sp, #4 + 0*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u0 * R1
+ umlal r3, r4, r0, r14
+
+ /* C interleaved with D */
+ ldr r0, [r1, #0*4] @ a[0]*2
+ ldr r14, [r1, #1*4] @ a[1]
+ mov r0, r0, asl #1
+ ldr r8, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1]
+ mov r7, r8, asl #1 @ a[2]*2
+ umull r11, r12, r14, r14 @ c' = a[1] * a[1]
+ ldr r14, [r1, #9*4] @ a[9]
+ umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2]
+ ldr r0, [r1, #3*4] @ a[3]*2
+ ldr r8, [r1, #8*4] @ a[8]
+ umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9]
+ mov r0, r0, asl #1
+ ldr r7, [r1, #4*4] @ a[4]*2
+ umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9]
+ ldr r14, [r1, #7*4] @ a[7]
+ umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8]
+ mov r7, r7, asl #1
+ ldr r0, [r1, #5*4] @ a[5]*2
+ umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8]
+ ldr r8, [r1, #6*4] @ a[6]
+ mov r0, r0, asl #1
+ umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7]
+ umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7]
+ umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6]
+ umlal r9, r10, r8, r8 @ d' += a[6] * a[6]
+
+ bic r0, r5, field_not_M @ u1 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u1 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t1 = c & M
+ str r14, [sp, #4 + 1*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u1 * R1
+ umlal r3, r4, r0, r14
+
+ /* D */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u2 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u2 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t2 = c & M
+ str r14, [sp, #4 + 2*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u2 * R1
+ umlal r3, r4, r0, r14
+
+ /* E interleaved with F */
+ ldr r7, [r1, #0*4] @ a[0]*2
+ ldr r0, [r1, #1*4] @ a[1]*2
+ ldr r14, [r1, #2*4] @ a[2]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #3*4] @ a[3]
+ ldr r2, [r1, #4*4]
+ umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3]
+ mov r0, r0, asl #1
+ umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4]
+ mov r2, r2, asl #1 @ a[4]*2
+ umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3]
+ ldr r8, [r1, #9*4] @ a[9]
+ umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2]
+ ldr r0, [r1, #5*4] @ a[5]*2
+ umlal r11, r12, r14, r14 @ c' += a[2] * a[2]
+ ldr r14, [r1, #8*4] @ a[8]
+ mov r0, r0, asl #1
+ umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9]
+ ldr r7, [r1, #6*4] @ a[6]*2
+ umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #7*4] @ a[7]
+ umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8]
+ umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8]
+ umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7]
+ umlal r9, r10, r8, r8 @ d' += a[7] * a[7]
+
+ bic r0, r5, field_not_M @ u3 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u3 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t3 = c & M
+ str r14, [sp, #4 + 3*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u3 * R1
+ umlal r3, r4, r0, r14
+
+ /* F */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u4 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u4 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t4 = c & M
+ str r14, [sp, #4 + 4*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u4 * R1
+ umlal r3, r4, r0, r14
+
+ /* G interleaved with H */
+ ldr r7, [r1, #0*4] @ a[0]*2
+ ldr r0, [r1, #1*4] @ a[1]*2
+ mov r7, r7, asl #1
+ ldr r8, [r1, #5*4] @ a[5]
+ ldr r2, [r1, #6*4] @ a[6]
+ umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5]
+ ldr r14, [r1, #4*4] @ a[4]
+ mov r0, r0, asl #1
+ umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6]
+ ldr r7, [r1, #2*4] @ a[2]*2
+ umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #3*4] @ a[3]
+ umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4]
+ mov r0, r2, asl #1 @ a[6]*2
+ umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4]
+ ldr r14, [r1, #9*4] @ a[9]
+ umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3]
+ ldr r7, [r1, #7*4] @ a[7]*2
+ umlal r11, r12, r8, r8 @ c' += a[3] * a[3]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9]
+ umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9]
+ umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8]
+ umlal r9, r10, r8, r8 @ d' += a[8] * a[8]
+
+ bic r0, r5, field_not_M @ u5 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u5 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t5 = c & M
+ str r14, [sp, #4 + 5*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u5 * R1
+ umlal r3, r4, r0, r14
+
+ /* H */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u6 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u6 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t6 = c & M
+ str r14, [sp, #4 + 6*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u6 * R1
+ umlal r3, r4, r0, r14
+
+ /* I interleaved with J */
+ ldr r7, [r1, #0*4] @ a[0]*2
+ ldr r0, [r1, #1*4] @ a[1]*2
+ mov r7, r7, asl #1
+ ldr r8, [r1, #7*4] @ a[7]
+ ldr r2, [r1, #8*4] @ a[8]
+ umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7]
+ ldr r14, [r1, #6*4] @ a[6]
+ mov r0, r0, asl #1
+ umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8]
+ ldr r7, [r1, #2*4] @ a[2]*2
+ umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7]
+ ldr r8, [r1, #5*4] @ a[5]
+ umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6]
+ ldr r0, [r1, #3*4] @ a[3]*2
+ mov r7, r7, asl #1
+ umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6]
+ ldr r14, [r1, #4*4] @ a[4]
+ mov r0, r0, asl #1
+ umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5]
+ mov r2, r2, asl #1 @ a[8]*2
+ umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5]
+ umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4]
+ umlal r11, r12, r14, r14 @ c' += a[4] * a[4]
+ ldr r8, [r1, #9*4] @ a[9]
+ umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9]
+ @ r8 will be used in J
+
+ bic r0, r5, field_not_M @ u7 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u7 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t7 = c & M
+ str r14, [sp, #4 + 7*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u7 * R1
+ umlal r3, r4, r0, r14
+
+ /* J */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ umlal r5, r6, r8, r8 @ d += a[9] * a[9]
+
+ bic r0, r5, field_not_M @ u8 = d & M
+ str r0, [sp, #4 + 8*4]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u8 * R0
+ umlal r3, r4, r0, r14
+
+ /******************************************
+ * compute and write back result
+ ******************************************
+ Allocation:
+ r0 r
+ r3:r4 c
+ r5:r6 d
+ r7 t0
+ r8 t1
+ r9 t2
+ r11 u8
+ r12 t9
+ r1,r2,r10,r14 scratch
+
+ Note: do not read from a[] after here, it may overlap with r[]
+ */
+ ldr r0, [sp, #0]
+ add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
+ ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
+ add r1, r0, #3*4
+ stmia r1, {r2,r7,r8,r9,r10}
+
+ bic r2, r3, field_not_M @ r[8] = c & M
+ str r2, [r0, #8*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u8 * R1
+ umlal r3, r4, r11, r14
+ movw r14, field_R0 @ c += d * R0
+ umlal r3, r4, r5, r14
+ adds r3, r3, r12 @ c += t9
+ adc r4, r4, #0
+
+ add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
+ ldmia r1, {r7,r8,r9}
+
+ ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
+ str r2, [r0, #9*4]
+ mov r3, r3, lsr #22 @ c >>= 22
+ orr r3, r3, r4, asl #10
+ mov r4, r4, lsr #22
+ movw r14, field_R1 << 4 @ c += d * (R1 << 4)
+ umlal r3, r4, r5, r14
+
+ movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
+ umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
+ adds r5, r5, r7 @ d.lo += t0
+ mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
+ adc r6, r6, 0 @ d.hi += carry
+
+ bic r2, r5, field_not_M @ r[0] = d & M
+ str r2, [r0, #0*4]
+
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
+ umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
+ adds r5, r5, r8 @ d.lo += t1
+ adc r6, r6, #0 @ d.hi += carry
+ adds r5, r5, r1 @ d.lo += tmp.lo
+ mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
+ adc r6, r6, r2 @ d.hi += carry + tmp.hi
+
+ bic r2, r5, field_not_M @ r[1] = d & M
+ str r2, [r0, #1*4]
+ mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
+ orr r5, r5, r6, asl #6
+
+ add r5, r5, r9 @ d += t2
+ str r5, [r0, #2*4] @ r[2] = d
+
+ add sp, sp, #48
+ ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
+ .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner
+
diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c
index 5a7c6376e0..cde5e2dbb4 100644
--- a/src/secp256k1/src/bench_ecdh.c
+++ b/src/secp256k1/src/bench_ecdh.c
@@ -28,7 +28,8 @@ static void bench_ecdh_setup(void* arg) {
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
};
- data->ctx = secp256k1_context_create(0);
+ /* create a context with no capabilities */
+ data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
for (i = 0; i < 32; i++) {
data->scalar[i] = i + 1;
}
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index 7809f5f8cf..0809f77bda 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -181,12 +181,12 @@ void bench_field_inverse_var(void* arg) {
}
}
-void bench_field_sqrt_var(void* arg) {
+void bench_field_sqrt(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 20000; i++) {
- secp256k1_fe_sqrt_var(&data->fe_x, &data->fe_x);
+ secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);
secp256k1_fe_add(&data->fe_x, &data->fe_y);
}
}
@@ -227,6 +227,15 @@ void bench_group_add_affine_var(void* arg) {
}
}
+void bench_group_jacobi_var(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 20000; i++) {
+ secp256k1_gej_has_quad_y_var(&data->gej_x);
+ }
+}
+
void bench_ecmult_wnaf(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
@@ -299,6 +308,21 @@ void bench_context_sign(void* arg) {
}
}
+#ifndef USE_NUM_NONE
+void bench_num_jacobi(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+ secp256k1_num nx, norder;
+
+ secp256k1_scalar_get_num(&nx, &data->scalar_x);
+ secp256k1_scalar_order_get_num(&norder);
+ secp256k1_scalar_get_num(&norder, &data->scalar_y);
+
+ for (i = 0; i < 200000; i++) {
+ secp256k1_num_jacobi(&nx, &norder);
+ }
+}
+#endif
int have_flag(int argc, char** argv, char *flag) {
char** argm = argv + argc;
@@ -333,12 +357,13 @@ int main(int argc, char **argv) {
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000);
- if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt_var", bench_field_sqrt_var, bench_setup, NULL, &data, 10, 20000);
+ if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000);
+ if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);
@@ -350,5 +375,8 @@ int main(int argc, char **argv) {
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20);
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200);
+#ifndef USE_NUM_NONE
+ if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000);
+#endif
return 0;
}
diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c
index 5718320cda..418defa0aa 100644
--- a/src/secp256k1/src/bench_verify.c
+++ b/src/secp256k1/src/bench_verify.c
@@ -11,6 +11,12 @@
#include "util.h"
#include "bench.h"
+#ifdef ENABLE_OPENSSL_TESTS
+#include <openssl/bn.h>
+#include <openssl/ecdsa.h>
+#include <openssl/obj_mac.h>
+#endif
+
typedef struct {
secp256k1_context *ctx;
unsigned char msg[32];
@@ -19,6 +25,9 @@ typedef struct {
size_t siglen;
unsigned char pubkey[33];
size_t pubkeylen;
+#ifdef ENABLE_OPENSSL_TESTS
+ EC_GROUP* ec_group;
+#endif
} benchmark_verify_t;
static void benchmark_verify(void* arg) {
@@ -40,6 +49,36 @@ static void benchmark_verify(void* arg) {
}
}
+#ifdef ENABLE_OPENSSL_TESTS
+static void benchmark_verify_openssl(void* arg) {
+ int i;
+ benchmark_verify_t* data = (benchmark_verify_t*)arg;
+
+ for (i = 0; i < 20000; i++) {
+ data->sig[data->siglen - 1] ^= (i & 0xFF);
+ data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
+ data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
+ {
+ EC_KEY *pkey = EC_KEY_new();
+ const unsigned char *pubkey = &data->pubkey[0];
+ int result;
+
+ CHECK(pkey != NULL);
+ result = EC_KEY_set_group(pkey, data->ec_group);
+ CHECK(result);
+ result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL;
+ CHECK(result);
+ result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0);
+ CHECK(result);
+ EC_KEY_free(pkey);
+ }
+ data->sig[data->siglen - 1] ^= (i & 0xFF);
+ data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
+ data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
+ }
+}
+#endif
+
int main(void) {
int i;
secp256k1_pubkey pubkey;
@@ -62,6 +101,11 @@ int main(void) {
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
+#ifdef ENABLE_OPENSSL_TESTS
+ data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1);
+ run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000);
+ EC_GROUP_free(data.ec_group);
+#endif
secp256k1_context_destroy(data.ctx);
return 0;
diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h
index d110b4bb1d..9a42e519bd 100644
--- a/src/secp256k1/src/ecdsa_impl.h
+++ b/src/secp256k1/src/ecdsa_impl.h
@@ -203,7 +203,9 @@ 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 *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) {
unsigned char c[32];
secp256k1_scalar sn, u1, u2;
+#if !defined(EXHAUSTIVE_TEST_ORDER)
secp256k1_fe xr;
+#endif
secp256k1_gej pubkeyj;
secp256k1_gej pr;
@@ -219,6 +221,21 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
if (secp256k1_gej_is_infinity(&pr)) {
return 0;
}
+
+#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 */
+ return secp256k1_scalar_eq(sigr, &computed_r);
+}
+#else
secp256k1_scalar_get_b32(c, sigr);
secp256k1_fe_set_b32(&xr, c);
@@ -252,6 +269,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
return 1;
}
return 0;
+#endif
}
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) {
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index 90ac94770e..0db314c48e 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -58,25 +58,27 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
int global_sign;
int skew = 0;
int word = 0;
+
/* 1 2 3 */
int u_last;
int u;
-#ifdef USE_ENDOMORPHISM
int flip;
int bit;
secp256k1_scalar neg_s;
int not_neg_one;
- /* If we are using the endomorphism, we cannot handle even numbers by negating
- * them, since we are working with 128-bit numbers whose negations would be 256
- * bits, eliminating the performance advantage. Instead we use a technique from
+ /* Note that we cannot handle even numbers by negating them to be odd, as is
+ * done in other implementations, since if our scalars were specified to have
+ * width < 256 for performance reasons, their negations would have width 256
+ * and we'd lose any performance benefit. Instead, we use a technique from
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
- * or 2 (for odd) to the number we are encoding, then compensating after the
- * multiplication. */
- /* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */
+ * or 2 (for odd) to the number we are encoding, returning a skew value indicating
+ * this, and having the caller compensate after doing the multiplication. */
+
+ /* Negative numbers will be negated to keep their bit representation below the maximum width */
flip = secp256k1_scalar_is_high(&s);
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
- bit = flip ^ (s.d[0] & 1);
+ bit = flip ^ !secp256k1_scalar_is_even(&s);
/* We check for negative one, since adding 2 to it will cause an overflow */
secp256k1_scalar_negate(&neg_s, &s);
not_neg_one = !secp256k1_scalar_is_one(&neg_s);
@@ -89,11 +91,6 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
global_sign = secp256k1_scalar_cond_negate(&s, flip);
global_sign *= not_neg_one * 2 - 1;
skew = 1 << bit;
-#else
- /* Otherwise, we just negate to force oddness */
- int is_even = secp256k1_scalar_is_even(&s);
- global_sign = secp256k1_scalar_cond_negate(&s, is_even);
-#endif
/* 4 */
u_last = secp256k1_scalar_shr_int(&s, w);
@@ -127,15 +124,13 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_ge tmpa;
secp256k1_fe Z;
+ int skew_1;
+ int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
#ifdef USE_ENDOMORPHISM
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
- int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
- int skew_1;
int skew_lam;
secp256k1_scalar q_1, q_lam;
-#else
- int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)];
#endif
int i;
@@ -145,18 +140,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
#ifdef USE_ENDOMORPHISM
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
- /* no need for zero correction when using endomorphism since even
- * numbers have one added to them anyway */
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1);
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1);
#else
- int is_zero = secp256k1_scalar_is_zero(scalar);
- /* the wNAF ladder cannot handle zero, so bump this to one .. we will
- * correct the result after the fact */
- sc.d[0] += is_zero;
- VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc));
-
- secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1);
+ skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1);
#endif
/* Calculate odd multiples of a.
@@ -179,21 +166,15 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
/* first loop iteration (separated out so we can directly set r, rather
* than having it start at infinity, get doubled several times, then have
* its new value added to it) */
-#ifdef USE_ENDOMORPHISM
i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
secp256k1_gej_set_ge(r, &tmpa);
-
+#ifdef USE_ENDOMORPHISM
i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
secp256k1_gej_add_ge(r, r, &tmpa);
-#else
- i = wnaf[WNAF_SIZE(WINDOW_A - 1)];
- VERIFY_CHECK(i != 0);
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
- secp256k1_gej_set_ge(r, &tmpa);
#endif
/* remaining loop iterations */
for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) {
@@ -202,59 +183,57 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
for (j = 0; j < WINDOW_A - 1; ++j) {
secp256k1_gej_double_nonzero(r, r, NULL);
}
-#ifdef USE_ENDOMORPHISM
+
n = wnaf_1[i];
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
-
+#ifdef USE_ENDOMORPHISM
n = wnaf_lam[i];
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
-#else
- n = wnaf[i];
- VERIFY_CHECK(n != 0);
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
- secp256k1_gej_add_ge(r, r, &tmpa);
#endif
}
secp256k1_fe_mul(&r->z, &r->z, &Z);
-#ifdef USE_ENDOMORPHISM
{
/* Correct for wNAF skew */
secp256k1_ge correction = *a;
secp256k1_ge_storage correction_1_stor;
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_storage correction_lam_stor;
+#endif
secp256k1_ge_storage a2_stor;
secp256k1_gej tmpj;
secp256k1_gej_set_ge(&tmpj, &correction);
secp256k1_gej_double_var(&tmpj, &tmpj, NULL);
secp256k1_ge_set_gej(&correction, &tmpj);
secp256k1_ge_to_storage(&correction_1_stor, a);
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_to_storage(&correction_lam_stor, a);
+#endif
secp256k1_ge_to_storage(&a2_stor, &correction);
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
+#endif
/* Apply the correction */
secp256k1_ge_from_storage(&correction, &correction_1_stor);
secp256k1_ge_neg(&correction, &correction);
secp256k1_gej_add_ge(r, r, &correction);
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_from_storage(&correction, &correction_lam_stor);
secp256k1_ge_neg(&correction, &correction);
secp256k1_ge_mul_lambda(&correction, &correction);
secp256k1_gej_add_ge(r, r, &correction);
- }
-#else
- /* correct for zero */
- r->infinity |= is_zero;
#endif
+ }
}
#endif
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index b63c4d8662..35f2546077 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -77,7 +77,7 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
}
}
- secp256k1_ge_set_all_gej_var(1024, prec, precj, cb);
+ secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb);
}
for (j = 0; j < 64; j++) {
for (i = 0; i < 16; i++) {
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index e6e5f47188..4e40104ad4 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -7,13 +7,29 @@
#ifndef _SECP256K1_ECMULT_IMPL_H_
#define _SECP256K1_ECMULT_IMPL_H_
+#include <string.h>
+
#include "group.h"
#include "scalar.h"
#include "ecmult.h"
+#if defined(EXHAUSTIVE_TEST_ORDER)
+/* We need to lower these values for exhaustive tests because
+ * the tables cannot have infinities in them (this breaks the
+ * affine-isomorphism stuff which tracks z-ratios) */
+# if EXHAUSTIVE_TEST_ORDER > 128
+# define WINDOW_A 5
+# define WINDOW_G 8
+# elif EXHAUSTIVE_TEST_ORDER > 8
+# define WINDOW_A 4
+# define WINDOW_G 4
+# else
+# define WINDOW_A 2
+# define WINDOW_G 2
+# endif
+#else
/* optimal for 128-bit and 256-bit exponents. */
#define WINDOW_A 5
-
/** larger numbers may result in slightly better performance, at the cost of
exponentially larger precomputed tables. */
#ifdef USE_ENDOMORPHISM
@@ -23,6 +39,7 @@
/** One table for window size 16: 1.375 MiB. */
#define WINDOW_G 16
#endif
+#endif
/** The number of entries a table with precomputed multiples needs to have. */
#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
@@ -101,7 +118,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge
/* Compute the odd multiples in Jacobian form. */
secp256k1_ecmult_odd_multiples_table(n, prej, zr, a);
/* Convert them in batch to affine coordinates. */
- secp256k1_ge_set_table_gej_var(n, prea, prej, zr);
+ secp256k1_ge_set_table_gej_var(prea, prej, zr, n);
/* Convert them to compact storage form. */
for (i = 0; i < n; i++) {
secp256k1_ge_to_storage(&pre[i], &prea[i]);
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index 2d52af5e36..bbb1ee866c 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -30,6 +30,8 @@
#error "Please select field implementation"
#endif
+#include "util.h"
+
/** Normalize a field element. */
static void secp256k1_fe_normalize(secp256k1_fe *r);
@@ -50,6 +52,9 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r);
/** Set a field element equal to a small integer. Resulting field element is normalized. */
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
+/** Sets a field element equal to zero, initializing all fields. */
+static void secp256k1_fe_clear(secp256k1_fe *a);
+
/** Verify whether a field element is zero. Requires the input to be normalized. */
static int secp256k1_fe_is_zero(const secp256k1_fe *a);
@@ -57,6 +62,9 @@ static int secp256k1_fe_is_zero(const secp256k1_fe *a);
static int secp256k1_fe_is_odd(const secp256k1_fe *a);
/** Compare two field elements. Requires magnitude-1 inputs. */
+static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
+
+/** Same as secp256k1_fe_equal, but may be variable time. */
static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
/** Compare two field elements. Requires both inputs to be normalized */
@@ -92,7 +100,10 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
* The input's magnitude can be at most 8. The output magnitude is 1 (but not
* guaranteed to be normalized). The result in r will always be a square
* itself. */
-static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a);
+static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a);
+
+/** Checks whether a field element is a quadratic residue. */
+static int secp256k1_fe_is_quad_var(const secp256k1_fe *a);
/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
* at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
@@ -104,7 +115,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);
/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be
* at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and
* outputs must not overlap in memory. */
-static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a);
+static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len);
/** Convert a field element to the storage type. */
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 212cc5396a..7b8c079608 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -7,8 +7,6 @@
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
#define _SECP256K1_FIELD_REPR_IMPL_H_
-#include <stdio.h>
-#include <string.h>
#include "util.h"
#include "num.h"
#include "field.h"
@@ -429,6 +427,14 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f
#endif
}
+#if defined(USE_EXTERNAL_ASM)
+
+/* External assembler implementation */
+void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b);
+void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a);
+
+#else
+
#ifdef VERIFY
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
#else
@@ -1037,7 +1043,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
VERIFY_BITS(r[2], 27);
/* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
-
+#endif
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
#ifdef VERIFY
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index b31e24ab81..7a99eb21ec 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -11,7 +11,6 @@
#include "libsecp256k1-config.h"
#endif
-#include <string.h>
#include "util.h"
#include "num.h"
#include "field.h"
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index 9280bb5ea2..0bf22bdd3e 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -137,7 +137,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
VERIFY_BITS(r[2], 52);
VERIFY_BITS(c, 63);
/* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += d * R + t3;;
+ c += d * R + t3;
VERIFY_BITS(c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[3] = c & M; c >>= 52;
@@ -259,7 +259,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
VERIFY_BITS(c, 63);
/* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += d * R + t3;;
+ c += d * R + t3;
VERIFY_BITS(c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[3] = c & M; c >>= 52;
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 77f4aae2f9..5127b279bc 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -21,6 +21,13 @@
#error "Please select field implementation"
#endif
+SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
+ secp256k1_fe na;
+ secp256k1_fe_negate(&na, a, 1);
+ secp256k1_fe_add(&na, b);
+ return secp256k1_fe_normalizes_to_zero(&na);
+}
+
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
secp256k1_fe_negate(&na, a, 1);
@@ -28,7 +35,7 @@ SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const
return secp256k1_fe_normalizes_to_zero_var(&na);
}
-static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) {
+static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
/** Given that p is congruent to 3 mod 4, we can compute the square root of
* a mod p as the (p+1)/4'th power of a.
*
@@ -123,7 +130,7 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) {
/* Check that a square root was actually calculated */
secp256k1_fe_sqr(&t1, r);
- return secp256k1_fe_equal_var(&t1, a);
+ return secp256k1_fe_equal(&t1, a);
}
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) {
@@ -253,7 +260,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) {
#endif
}
-static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a) {
+static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len) {
secp256k1_fe u;
size_t i;
if (len < 1) {
@@ -280,4 +287,29 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k
r[0] = u;
}
+static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
+#ifndef USE_NUM_NONE
+ unsigned char b[32];
+ secp256k1_num n;
+ secp256k1_num m;
+ /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
+ static const unsigned char prime[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,0xFE,0xFF,0xFF,0xFC,0x2F
+ };
+
+ secp256k1_fe c = *a;
+ secp256k1_fe_normalize_var(&c);
+ secp256k1_fe_get_b32(b, &c);
+ secp256k1_num_set_bin(&n, b, 32);
+ secp256k1_num_set_bin(&m, prime, 32);
+ return secp256k1_num_jacobi(&n, &m) >= 0;
+#else
+ secp256k1_fe r;
+ return secp256k1_fe_sqrt(&r, a);
+#endif
+}
+
#endif
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index ebfe1ca70c..4957b248fe 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -47,7 +47,7 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se
* and a Y coordinate that is a quadratic residue modulo p. The return value
* is true iff a coordinate with the given X coordinate exists.
*/
-static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x);
+static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x);
/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness
* for Y. Return value indicates whether the result is valid. */
@@ -65,12 +65,12 @@ static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
-static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb);
+static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb);
/** Set a batch of group elements equal to the inputs given in jacobian
* coordinates (with known z-ratios). zr must contain the known z-ratios such
* that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */
-static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr);
+static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len);
/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
* the same global z "denominator". zr must contain the known z-ratios such
@@ -94,6 +94,9 @@ static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a);
/** Check whether a group element is the point at infinity. */
static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
+/** Check whether a group element's y coordinate is a quadratic residue. */
+static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);
+
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).
* a may not be zero. Constant time. */
static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 42e2f6e6eb..2e192b62fd 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -7,12 +7,57 @@
#ifndef _SECP256K1_GROUP_IMPL_H_
#define _SECP256K1_GROUP_IMPL_H_
-#include <string.h>
-
#include "num.h"
#include "field.h"
#include "group.h"
+/* These points can be generated in sage as follows:
+ *
+ * 0. Setup a worksheet with the following parameters.
+ * b = 4 # whatever CURVE_B will be set to
+ * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
+ * C = EllipticCurve ([F (0), F (b)])
+ *
+ * 1. Determine all the small orders available to you. (If there are
+ * no satisfactory ones, go back and change b.)
+ * print C.order().factor(limit=1000)
+ *
+ * 2. Choose an order as one of the prime factors listed in the above step.
+ * (You can also multiply some to get a composite order, though the
+ * tests will crash trying to invert scalars during signing.) We take a
+ * random point and scale it to drop its order to the desired value.
+ * There is some probability this won't work; just try again.
+ * order = 199
+ * P = C.random_point()
+ * P = (int(P.order()) / int(order)) * P
+ * assert(P.order() == order)
+ *
+ * 3. Print the values. You'll need to use a vim macro or something to
+ * split the hex output into 4-byte chunks.
+ * print "%x %x" % P.xy()
+ */
+#if defined(EXHAUSTIVE_TEST_ORDER)
+# if EXHAUSTIVE_TEST_ORDER == 199
+const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
+ 0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069,
+ 0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18,
+ 0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868,
+ 0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED
+);
+
+const int CURVE_B = 4;
+# elif EXHAUSTIVE_TEST_ORDER == 13
+const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
+ 0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0,
+ 0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15,
+ 0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e,
+ 0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac
+);
+const int CURVE_B = 2;
+# else
+# error No known generator for the specified exhaustive test group order.
+# endif
+#else
/** Generator for secp256k1, value 'g' defined in
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
*/
@@ -23,8 +68,11 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
);
+const int CURVE_B = 7;
+#endif
+
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
- secp256k1_fe zi2;
+ secp256k1_fe zi2;
secp256k1_fe zi3;
secp256k1_fe_sqr(&zi2, zi);
secp256k1_fe_mul(&zi3, &zi2, zi);
@@ -78,7 +126,7 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
r->y = a->y;
}
-static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb) {
+static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) {
secp256k1_fe *az;
secp256k1_fe *azi;
size_t i;
@@ -91,7 +139,7 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp
}
azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count);
- secp256k1_fe_inv_all_var(count, azi, az);
+ secp256k1_fe_inv_all_var(azi, az, count);
free(az);
count = 0;
@@ -104,7 +152,7 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp
free(azi);
}
-static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr) {
+static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) {
size_t i = len - 1;
secp256k1_fe zi;
@@ -147,9 +195,15 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp
static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
r->infinity = 1;
- secp256k1_fe_set_int(&r->x, 0);
- secp256k1_fe_set_int(&r->y, 0);
- secp256k1_fe_set_int(&r->z, 0);
+ secp256k1_fe_clear(&r->x);
+ secp256k1_fe_clear(&r->y);
+ 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) {
@@ -165,19 +219,19 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
secp256k1_fe_clear(&r->y);
}
-static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) {
+static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
secp256k1_fe x2, x3, c;
r->x = *x;
secp256k1_fe_sqr(&x2, x);
secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0;
- secp256k1_fe_set_int(&c, 7);
+ secp256k1_fe_set_int(&c, CURVE_B);
secp256k1_fe_add(&c, &x3);
- return secp256k1_fe_sqrt_var(&r->y, &c);
+ return secp256k1_fe_sqrt(&r->y, &c);
}
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
- if (!secp256k1_ge_set_xquad_var(r, x)) {
+ if (!secp256k1_ge_set_xquad(r, x)) {
return 0;
}
secp256k1_fe_normalize_var(&r->y);
@@ -230,7 +284,7 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
secp256k1_fe_sqr(&z2, &a->z);
secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
- secp256k1_fe_mul_int(&z6, 7);
+ secp256k1_fe_mul_int(&z6, CURVE_B);
secp256k1_fe_add(&x3, &z6);
secp256k1_fe_normalize_weak(&x3);
return secp256k1_fe_equal_var(&y2, &x3);
@@ -244,18 +298,30 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
/* y^2 = x^3 + 7 */
secp256k1_fe_sqr(&y2, &a->y);
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
- secp256k1_fe_set_int(&c, 7);
+ secp256k1_fe_set_int(&c, CURVE_B);
secp256k1_fe_add(&x3, &c);
secp256k1_fe_normalize_weak(&x3);
return secp256k1_fe_equal_var(&y2, &x3);
}
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
- /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */
+ /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
+ *
+ * Note that there is an implementation described at
+ * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
+ * which trades a multiply for a square, but in practice this is actually slower,
+ * mainly because it requires more normalizations.
+ */
secp256k1_fe t1,t2,t3,t4;
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
+ *
+ * Having said this, if this function receives a point on a sextic twist, e.g. by
+ * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
+ * since -6 does have a cube root mod p. For this point, this function will not set
+ * the infinity flag even though the point doubles to infinity, and the result
+ * point will be gibberish (z = 0 but infinity = 0).
*/
r->infinity = a->infinity;
if (r->infinity) {
@@ -623,4 +689,18 @@ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
}
#endif
+static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
+ secp256k1_fe yz;
+
+ if (a->infinity) {
+ return 0;
+ }
+
+ /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as
+ * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z
+ is */
+ secp256k1_fe_mul(&yz, &a->y, &a->z);
+ return secp256k1_fe_is_quad_var(&yz);
+}
+
#endif
diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h
index 0ff01e63fa..fca98cab9f 100644
--- a/src/secp256k1/src/hash.h
+++ b/src/secp256k1/src/hash.h
@@ -11,7 +11,7 @@
#include <stdint.h>
typedef struct {
- uint32_t s[32];
+ uint32_t s[8];
uint32_t buf[16]; /* In big endian */
size_t bytes;
} secp256k1_sha256_t;
diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h
index ae55df6d8a..b47e65f830 100644
--- a/src/secp256k1/src/hash_impl.h
+++ b/src/secp256k1/src/hash_impl.h
@@ -269,15 +269,13 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
rng->retry = 0;
}
-
+#undef BE32
#undef Round
-#undef sigma0
#undef sigma1
-#undef Sigma0
+#undef sigma0
#undef Sigma1
-#undef Ch
+#undef Sigma0
#undef Maj
-#undef ReadBE32
-#undef WriteBE32
+#undef Ch
#endif
diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
index 90a498eaa2..1c67802fba 100644
--- a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
+++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
@@ -1,60 +1,446 @@
+/*
+ * Copyright 2013 Google Inc.
+ * Copyright 2014-2016 the libsecp256k1 contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package org.bitcoin;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.math.BigInteger;
import com.google.common.base.Preconditions;
-
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import static org.bitcoin.NativeSecp256k1Util.*;
/**
- * This class holds native methods to handle ECDSA verification.
- * You can find an example library that can be used for this at
- * https://github.com/sipa/secp256k1
+ * <p>This class holds native methods to handle ECDSA verification.</p>
+ *
+ * <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
+ *
+ * <p>To build secp256k1 for use with bitcoinj, run
+ * `./configure --enable-jni --enable-experimental --enable-module-ecdh`
+ * and `make` then copy `.libs/libsecp256k1.so` to your system library path
+ * or point the JVM to the folder containing it with -Djava.library.path
+ * </p>
*/
public class NativeSecp256k1 {
- public static final boolean enabled;
- static {
- boolean isEnabled = true;
- try {
- System.loadLibrary("javasecp256k1");
- } catch (UnsatisfiedLinkError e) {
- isEnabled = false;
- }
- enabled = isEnabled;
- }
-
+
+ private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ private static final Lock r = rwl.readLock();
+ private static final Lock w = rwl.writeLock();
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
/**
* Verifies the given secp256k1 signature in native code.
* Calling when enabled == false is undefined (probably library not loaded)
- *
+ *
* @param data The data which was signed, must be exactly 32 bytes
* @param signature The signature
* @param pub The public key which did the signing
*/
- public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
+ public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
ByteBuffer byteBuff = nativeECDSABuffer.get();
- if (byteBuff == null) {
- byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
+ if (byteBuff == null || byteBuff.capacity() < 520) {
+ byteBuff = ByteBuffer.allocateDirect(520);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(data);
- byteBuff.putInt(signature.length);
- byteBuff.putInt(pub.length);
byteBuff.put(signature);
byteBuff.put(pub);
- return secp256k1_ecdsa_verify(byteBuff) == 1;
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
+ } finally {
+ r.unlock();
+ }
+ }
+
+ /**
+ * libsecp256k1 Create an ECDSA signature.
+ *
+ * @param data Message hash, 32 bytes
+ * @param key Secret key, 32 bytes
+ *
+ * Return values
+ * @param sig byte array of signature
+ */
+ public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
+ Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
+ byteBuff = ByteBuffer.allocateDirect(32 + 32);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(data);
+ byteBuff.put(sec);
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] sigArr = retByteArray[0];
+ int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(sigArr.length, sigLen, "Got bad signature length.");
+
+ return retVal == 0 ? new byte[0] : sigArr;
+ }
+
+ /**
+ * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
+ *
+ * @param seckey ECDSA Secret key, 32 bytes
+ */
+ public static boolean secKeyVerify(byte[] seckey) {
+ Preconditions.checkArgument(seckey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < seckey.length) {
+ byteBuff = ByteBuffer.allocateDirect(seckey.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seckey);
+
+ r.lock();
+ try {
+ return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
+ } finally {
+ r.unlock();
+ }
+ }
+
+
+ /**
+ * libsecp256k1 Compute Pubkey - computes public key from secret key
+ *
+ * @param seckey ECDSA Secret key, 32 bytes
+ *
+ * Return values
+ * @param pubkey ECDSA Public key, 33 or 65 bytes
+ */
+ //TODO add a 'compressed' arg
+ public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
+ Preconditions.checkArgument(seckey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < seckey.length) {
+ byteBuff = ByteBuffer.allocateDirect(seckey.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seckey);
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] pubArr = retByteArray[0];
+ int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
+
+ return retVal == 0 ? new byte[0]: pubArr;
+ }
+
+ /**
+ * libsecp256k1 Cleanup - This destroys the secp256k1 context object
+ * This should be called at the end of the program for proper cleanup of the context.
+ */
+ public static synchronized void cleanup() {
+ w.lock();
+ try {
+ secp256k1_destroy_context(Secp256k1Context.getContext());
+ } finally {
+ w.unlock();
+ }
+ }
+
+ public static long cloneContext() {
+ r.lock();
+ try {
+ return secp256k1_ctx_clone(Secp256k1Context.getContext());
+ } finally { r.unlock(); }
+ }
+
+ /**
+ * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param seckey 32-byte seckey
+ */
+ public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(privkey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(privkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] privArr = retByteArray[0];
+
+ int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(privArr.length, privLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return privArr;
+ }
+
+ /**
+ * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param seckey 32-byte seckey
+ */
+ public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(privkey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(privkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] privArr = retByteArray[0];
+
+ int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(privArr.length, privLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return privArr;
+ }
+
+ /**
+ * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param pubkey 32-byte seckey
+ */
+ public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(pubkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
+ } finally {
+ r.unlock();
+ }
+
+ byte[] pubArr = retByteArray[0];
+
+ int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return pubArr;
+ }
+
+ /**
+ * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param pubkey 32-byte seckey
+ */
+ public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(pubkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
+ } finally {
+ r.unlock();
+ }
+
+ byte[] pubArr = retByteArray[0];
+
+ int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return pubArr;
}
/**
- * @param byteBuff signature format is byte[32] data,
- * native-endian int signatureLength, native-endian int pubkeyLength,
- * byte[signatureLength] signature, byte[pubkeyLength] pub
- * @returns 1 for valid signature, anything else for invalid
+ * libsecp256k1 create ECDH secret - constant time ECDH calculation
+ *
+ * @param seckey byte array of secret key used in exponentiaion
+ * @param pubkey byte array of public key used in exponentiaion
*/
- private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
+ public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
+ Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
+ byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seckey);
+ byteBuff.put(pubkey);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
+ } finally {
+ r.unlock();
+ }
+
+ byte[] resArr = retByteArray[0];
+ int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+
+ assertEquals(resArr.length, 32, "Got bad result length.");
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return resArr;
+ }
+
+ /**
+ * libsecp256k1 randomize - updates the context randomization
+ *
+ * @param seed 32-byte random seed
+ */
+ public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
+ Preconditions.checkArgument(seed.length == 32 || seed == null);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < seed.length) {
+ byteBuff = ByteBuffer.allocateDirect(seed.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seed);
+
+ w.lock();
+ try {
+ return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
+ } finally {
+ w.unlock();
+ }
+ }
+
+ private static native long secp256k1_ctx_clone(long context);
+
+ private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
+
+ private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
+
+ private static native void secp256k1_destroy_context(long context);
+
+ private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
+
+ private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
+
+ private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
+
+ private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
+
}
diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java
new file mode 100644
index 0000000000..c00d08899b
--- /dev/null
+++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java
@@ -0,0 +1,226 @@
+package org.bitcoin;
+
+import com.google.common.io.BaseEncoding;
+import java.util.Arrays;
+import java.math.BigInteger;
+import javax.xml.bind.DatatypeConverter;
+import static org.bitcoin.NativeSecp256k1Util.*;
+
+/**
+ * This class holds test cases defined for testing this library.
+ */
+public class NativeSecp256k1Test {
+
+ //TODO improve comments/add more tests
+ /**
+ * This tests verify() for a valid signature
+ */
+ public static void testVerifyPos() throws AssertFailException{
+ boolean result = false;
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+
+ result = NativeSecp256k1.verify( data, sig, pub);
+ assertEquals( result, true , "testVerifyPos");
+ }
+
+ /**
+ * This tests verify() for a non-valid signature
+ */
+ public static void testVerifyNeg() throws AssertFailException{
+ boolean result = false;
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
+ byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+
+ result = NativeSecp256k1.verify( data, sig, pub);
+ //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
+ assertEquals( result, false , "testVerifyNeg");
+ }
+
+ /**
+ * This tests secret key verify() for a valid secretkey
+ */
+ public static void testSecKeyVerifyPos() throws AssertFailException{
+ boolean result = false;
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ result = NativeSecp256k1.secKeyVerify( sec );
+ //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
+ assertEquals( result, true , "testSecKeyVerifyPos");
+ }
+
+ /**
+ * This tests secret key verify() for a invalid secretkey
+ */
+ public static void testSecKeyVerifyNeg() throws AssertFailException{
+ boolean result = false;
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
+
+ result = NativeSecp256k1.secKeyVerify( sec );
+ //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
+ assertEquals( result, false , "testSecKeyVerifyNeg");
+ }
+
+ /**
+ * This tests public key create() for a valid secretkey
+ */
+ public static void testPubKeyCreatePos() throws AssertFailException{
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.computePubkey( sec);
+ String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos");
+ }
+
+ /**
+ * This tests public key create() for a invalid secretkey
+ */
+ public static void testPubKeyCreateNeg() throws AssertFailException{
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.computePubkey( sec);
+ String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( pubkeyString, "" , "testPubKeyCreateNeg");
+ }
+
+ /**
+ * This tests sign() for a valid secretkey
+ */
+ public static void testSignPos() throws AssertFailException{
+
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.sign(data, sec);
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
+ }
+
+ /**
+ * This tests sign() for a invalid secretkey
+ */
+ public static void testSignNeg() throws AssertFailException{
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.sign(data, sec);
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString, "" , "testSignNeg");
+ }
+
+ /**
+ * This tests private key tweak-add
+ */
+ public static void testPrivKeyTweakAdd_1() throws AssertFailException {
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1");
+ }
+
+ /**
+ * This tests private key tweak-mul
+ */
+ public static void testPrivKeyTweakMul_1() throws AssertFailException {
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1");
+ }
+
+ /**
+ * This tests private key tweak-add uncompressed
+ */
+ public static void testPrivKeyTweakAdd_2() throws AssertFailException {
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2");
+ }
+
+ /**
+ * This tests private key tweak-mul uncompressed
+ */
+ public static void testPrivKeyTweakMul_2() throws AssertFailException {
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2");
+ }
+
+ /**
+ * This tests seed randomization
+ */
+ public static void testRandomize() throws AssertFailException {
+ byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
+ boolean result = NativeSecp256k1.randomize(seed);
+ assertEquals( result, true, "testRandomize");
+ }
+
+ public static void testCreateECDHSecret() throws AssertFailException{
+
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);
+ String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret");
+ }
+
+ public static void main(String[] args) throws AssertFailException{
+
+
+ System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n");
+
+ assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" );
+
+ //Test verify() success/fail
+ testVerifyPos();
+ testVerifyNeg();
+
+ //Test secKeyVerify() success/fail
+ testSecKeyVerifyPos();
+ testSecKeyVerifyNeg();
+
+ //Test computePubkey() success/fail
+ testPubKeyCreatePos();
+ testPubKeyCreateNeg();
+
+ //Test sign() success/fail
+ testSignPos();
+ testSignNeg();
+
+ //Test privKeyTweakAdd() 1
+ testPrivKeyTweakAdd_1();
+
+ //Test privKeyTweakMul() 2
+ testPrivKeyTweakMul_1();
+
+ //Test privKeyTweakAdd() 3
+ testPrivKeyTweakAdd_2();
+
+ //Test privKeyTweakMul() 4
+ testPrivKeyTweakMul_2();
+
+ //Test randomize()
+ testRandomize();
+
+ //Test ECDH
+ testCreateECDHSecret();
+
+ NativeSecp256k1.cleanup();
+
+ System.out.println(" All tests passed." );
+
+ }
+}
diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java
new file mode 100644
index 0000000000..04732ba044
--- /dev/null
+++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014-2016 the libsecp256k1 contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.bitcoin;
+
+public class NativeSecp256k1Util{
+
+ public static void assertEquals( int val, int val2, String message ) throws AssertFailException{
+ if( val != val2 )
+ throw new AssertFailException("FAIL: " + message);
+ }
+
+ public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{
+ if( val != val2 )
+ throw new AssertFailException("FAIL: " + message);
+ else
+ System.out.println("PASS: " + message);
+ }
+
+ public static void assertEquals( String val, String val2, String message ) throws AssertFailException{
+ if( !val.equals(val2) )
+ throw new AssertFailException("FAIL: " + message);
+ else
+ System.out.println("PASS: " + message);
+ }
+
+ public static class AssertFailException extends Exception {
+ public AssertFailException(String message) {
+ super( message );
+ }
+ }
+}
diff --git a/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java
new file mode 100644
index 0000000000..216c986a8b
--- /dev/null
+++ b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014-2016 the libsecp256k1 contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.bitcoin;
+
+/**
+ * This class holds the context reference used in native methods
+ * to handle ECDSA operations.
+ */
+public class Secp256k1Context {
+ private static final boolean enabled; //true if the library is loaded
+ private static final long context; //ref to pointer to context obj
+
+ static { //static initializer
+ boolean isEnabled = true;
+ long contextRef = -1;
+ try {
+ System.loadLibrary("secp256k1");
+ contextRef = secp256k1_init_context();
+ } catch (UnsatisfiedLinkError e) {
+ System.out.println("UnsatisfiedLinkError: " + e.toString());
+ isEnabled = false;
+ }
+ enabled = isEnabled;
+ context = contextRef;
+ }
+
+ public static boolean isEnabled() {
+ return enabled;
+ }
+
+ public static long getContext() {
+ if(!enabled) return -1; //sanity check
+ return context;
+ }
+
+ private static native long secp256k1_init_context();
+}
diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
index bb4cd70728..bcef7b32ce 100644
--- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
+++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
@@ -1,23 +1,377 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
#include "org_bitcoin_NativeSecp256k1.h"
#include "include/secp256k1.h"
+#include "include/secp256k1_ecdh.h"
+#include "include/secp256k1_recovery.h"
-JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
- (JNIEnv* env, jclass classObject, jobject byteBufferObject)
+
+SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
+ (JNIEnv* env, jclass classObject, jlong ctx_l)
+{
+ const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx);
+
+ (void)classObject;(void)env;
+
+ return ctx_clone_l;
+
+}
+
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
{
- unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
- int sigLen = *((int*)(data + 32));
- int pubLen = *((int*)(data + 32 + 4));
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+
+ (void)classObject;
+
+ return secp256k1_context_randomize(ctx, seed);
- return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen);
}
-static void __javasecp256k1_attach(void) __attribute__((constructor));
-static void __javasecp256k1_detach(void) __attribute__((destructor));
+SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
+ (JNIEnv* env, jclass classObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ secp256k1_context_destroy(ctx);
-static void __javasecp256k1_attach(void) {
- secp256k1_start(SECP256K1_START_VERIFY);
+ (void)classObject;(void)env;
}
-static void __javasecp256k1_detach(void) {
- secp256k1_stop();
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* sigdata = { (unsigned char*) (data + 32) };
+ const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };
+
+ secp256k1_ecdsa_signature sig;
+ secp256k1_pubkey pubkey;
+
+ int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
+
+ if( ret ) {
+ ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
+
+ if( ret ) {
+ ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);
+ }
+ }
+
+ (void)classObject;
+
+ return ret;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ unsigned char* secKey = (unsigned char*) (data + 32);
+
+ jobjectArray retArray;
+ jbyteArray sigArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ secp256k1_ecdsa_signature sig[72];
+
+ int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );
+
+ unsigned char outputSer[72];
+ size_t outputLen = 72;
+
+ if( ret ) {
+ int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ sigArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+
+ (void)classObject;
+
+ return secp256k1_ec_seckey_verify(ctx, secKey);
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+
+ secp256k1_pubkey pubkey;
+
+ jobjectArray retArray;
+ jbyteArray pubkeyArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);
+
+ unsigned char outputSer[65];
+ size_t outputLen = 65;
+
+ if( ret ) {
+ int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ pubkeyArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (privkey + 32);
+
+ jobjectArray retArray;
+ jbyteArray privArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ int privkeylen = 32;
+
+ int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak);
+
+ intsarray[0] = privkeylen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ privArray = (*env)->NewByteArray(env, privkeylen);
+ (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
+ (*env)->SetObjectArrayElement(env, retArray, 0, privArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (privkey + 32);
+
+ jobjectArray retArray;
+ jbyteArray privArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ int privkeylen = 32;
+
+ int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak);
+
+ intsarray[0] = privkeylen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ privArray = (*env)->NewByteArray(env, privkeylen);
+ (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
+ (*env)->SetObjectArrayElement(env, retArray, 0, privArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/
+ unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (pkey + publen);
+
+ jobjectArray retArray;
+ jbyteArray pubArray, intsByteArray;
+ unsigned char intsarray[2];
+ unsigned char outputSer[65];
+ size_t outputLen = 65;
+
+ secp256k1_pubkey pubkey;
+ int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
+
+ if( ret ) {
+ ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak);
+ }
+
+ if( ret ) {
+ int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ pubArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (pkey + publen);
+
+ jobjectArray retArray;
+ jbyteArray pubArray, intsByteArray;
+ unsigned char intsarray[2];
+ unsigned char outputSer[65];
+ size_t outputLen = 65;
+
+ secp256k1_pubkey pubkey;
+ int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
+
+ if ( ret ) {
+ ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak);
+ }
+
+ if( ret ) {
+ int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ pubArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine
+ (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys)
+{
+ (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys;
+
+ return 0;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* pubdata = (const unsigned char*) (secdata + 32);
+
+ jobjectArray retArray;
+ jbyteArray outArray, intsByteArray;
+ unsigned char intsarray[1];
+ secp256k1_pubkey pubkey;
+ unsigned char nonce_res[32];
+ size_t outputLen = 32;
+
+ int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
+
+ if (ret) {
+ ret = secp256k1_ecdh(
+ ctx,
+ nonce_res,
+ &pubkey,
+ secdata
+ );
+ }
+
+ intsarray[0] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ outArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res);
+ (*env)->SetObjectArrayElement(env, retArray, 0, outArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 1);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
}
diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
index d7fb004fa8..fe613c9e9e 100644
--- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
+++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
@@ -1,5 +1,6 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
+#include "include/secp256k1.h"
/* Header for class org_bitcoin_NativeSecp256k1 */
#ifndef _Included_org_bitcoin_NativeSecp256k1
@@ -9,11 +10,108 @@ extern "C" {
#endif
/*
* Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ctx_clone
+ * Signature: (J)J
+ */
+SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_context_randomize
+ * Signature: (Ljava/nio/ByteBuffer;J)I
+ */
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_privkey_tweak_add
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_privkey_tweak_mul
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_pubkey_tweak_add
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
+ (JNIEnv *, jclass, jobject, jlong, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_pubkey_tweak_mul
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
+ (JNIEnv *, jclass, jobject, jlong, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_destroy_context
+ * Signature: (J)V
+ */
+SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ecdsa_verify
- * Signature: (Ljava/nio/ByteBuffer;)I
+ * Signature: (Ljava/nio/ByteBuffer;JII)I
+ */
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
+ (JNIEnv *, jclass, jobject, jlong, jint, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ecdsa_sign
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ec_seckey_verify
+ * Signature: (Ljava/nio/ByteBuffer;J)I
+ */
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ec_pubkey_create
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ec_pubkey_parse
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
+ (JNIEnv *, jclass, jobject, jlong, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ecdh
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
*/
-JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
- (JNIEnv *, jclass, jobject);
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen);
+
#ifdef __cplusplus
}
diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c
new file mode 100644
index 0000000000..a52939e7e7
--- /dev/null
+++ b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include "org_bitcoin_Secp256k1Context.h"
+#include "include/secp256k1.h"
+
+SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
+ (JNIEnv* env, jclass classObject)
+{
+ secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+
+ (void)classObject;(void)env;
+
+ return (uintptr_t)ctx;
+}
+
diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h
new file mode 100644
index 0000000000..0d2bc84b7f
--- /dev/null
+++ b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h
@@ -0,0 +1,22 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+#include "include/secp256k1.h"
+/* Header for class org_bitcoin_Secp256k1Context */
+
+#ifndef _Included_org_bitcoin_Secp256k1Context
+#define _Included_org_bitcoin_Secp256k1Context
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_bitcoin_Secp256k1Context
+ * Method: secp256k1_init_context
+ * Signature: ()J
+ */
+SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/secp256k1/src/modules/ecdh/Makefile.am.include b/src/secp256k1/src/modules/ecdh/Makefile.am.include
index 670b9c1152..e3088b4697 100644
--- a/src/secp256k1/src/modules/ecdh/Makefile.am.include
+++ b/src/secp256k1/src/modules/ecdh/Makefile.am.include
@@ -4,5 +4,5 @@ noinst_HEADERS += src/modules/ecdh/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_ecdh
bench_ecdh_SOURCES = src/bench_ecdh.c
-bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
diff --git a/src/secp256k1/src/modules/recovery/Makefile.am.include b/src/secp256k1/src/modules/recovery/Makefile.am.include
index 5de3ea33ea..bf23c26e71 100644
--- a/src/secp256k1/src/modules/recovery/Makefile.am.include
+++ b/src/secp256k1/src/modules/recovery/Makefile.am.include
@@ -4,5 +4,5 @@ noinst_HEADERS += src/modules/recovery/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_recover
bench_recover_SOURCES = src/bench_recover.c
-bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h
index ec42f4bb6c..86f2f0cb2b 100644..100755
--- a/src/secp256k1/src/modules/recovery/main_impl.h
+++ b/src/secp256k1/src/modules/recovery/main_impl.h
@@ -138,16 +138,15 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
/* Fail if the secret key is invalid. */
if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
+ unsigned char nonce32[32];
unsigned int count = 0;
secp256k1_scalar_set_b32(&msg, msg32, NULL);
while (1) {
- unsigned char nonce32[32];
ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
if (!ret) {
break;
}
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
- memset(nonce32, 0, 32);
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
break;
@@ -155,6 +154,7 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd
}
count++;
}
+ memset(nonce32, 0, 32);
secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non);
secp256k1_scalar_clear(&sec);
diff --git a/src/secp256k1/src/modules/schnorr/Makefile.am.include b/src/secp256k1/src/modules/schnorr/Makefile.am.include
deleted file mode 100644
index b3bfa7d5cc..0000000000
--- a/src/secp256k1/src/modules/schnorr/Makefile.am.include
+++ /dev/null
@@ -1,10 +0,0 @@
-include_HEADERS += include/secp256k1_schnorr.h
-noinst_HEADERS += src/modules/schnorr/main_impl.h
-noinst_HEADERS += src/modules/schnorr/schnorr.h
-noinst_HEADERS += src/modules/schnorr/schnorr_impl.h
-noinst_HEADERS += src/modules/schnorr/tests_impl.h
-if USE_BENCHMARK
-noinst_PROGRAMS += bench_schnorr_verify
-bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c
-bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
-endif
diff --git a/src/secp256k1/src/modules/schnorr/main_impl.h b/src/secp256k1/src/modules/schnorr/main_impl.h
deleted file mode 100644
index fa176a1767..0000000000
--- a/src/secp256k1/src/modules/schnorr/main_impl.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/**********************************************************************
- * Copyright (c) 2014-2015 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
- **********************************************************************/
-
-#ifndef SECP256K1_MODULE_SCHNORR_MAIN
-#define SECP256K1_MODULE_SCHNORR_MAIN
-
-#include "include/secp256k1_schnorr.h"
-#include "modules/schnorr/schnorr_impl.h"
-
-static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) {
- secp256k1_sha256_t sha;
- secp256k1_sha256_initialize(&sha);
- secp256k1_sha256_write(&sha, r32, 32);
- secp256k1_sha256_write(&sha, msg32, 32);
- secp256k1_sha256_finalize(&sha, h32);
-}
-
-static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 ";
-
-int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
- secp256k1_scalar sec, non;
- int ret = 0;
- int overflow = 0;
- unsigned int count = 0;
- VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
- ARG_CHECK(msg32 != NULL);
- ARG_CHECK(sig64 != NULL);
- ARG_CHECK(seckey != NULL);
- if (noncefp == NULL) {
- noncefp = secp256k1_nonce_function_default;
- }
-
- secp256k1_scalar_set_b32(&sec, seckey, NULL);
- while (1) {
- unsigned char nonce32[32];
- ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count);
- if (!ret) {
- break;
- }
- secp256k1_scalar_set_b32(&non, nonce32, &overflow);
- memset(nonce32, 0, 32);
- if (!secp256k1_scalar_is_zero(&non) && !overflow) {
- if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) {
- break;
- }
- }
- count++;
- }
- if (!ret) {
- memset(sig64, 0, 64);
- }
- secp256k1_scalar_clear(&non);
- secp256k1_scalar_clear(&sec);
- return ret;
-}
-
-int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) {
- secp256k1_ge q;
- VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
- ARG_CHECK(msg32 != NULL);
- ARG_CHECK(sig64 != NULL);
- ARG_CHECK(pubkey != NULL);
-
- secp256k1_pubkey_load(ctx, &q, pubkey);
- return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32);
-}
-
-int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) {
- secp256k1_ge q;
-
- VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
- ARG_CHECK(msg32 != NULL);
- ARG_CHECK(sig64 != NULL);
- ARG_CHECK(pubkey != NULL);
-
- if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) {
- secp256k1_pubkey_save(pubkey, &q);
- return 1;
- } else {
- memset(pubkey, 0, sizeof(*pubkey));
- return 0;
- }
-}
-
-int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) {
- int count = 0;
- int ret = 1;
- secp256k1_gej Qj;
- secp256k1_ge Q;
- secp256k1_scalar sec;
-
- VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
- ARG_CHECK(msg32 != NULL);
- ARG_CHECK(sec32 != NULL);
- ARG_CHECK(pubnonce != NULL);
- ARG_CHECK(privnonce32 != NULL);
-
- if (noncefp == NULL) {
- noncefp = secp256k1_nonce_function_default;
- }
-
- do {
- int overflow;
- ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++);
- if (!ret) {
- break;
- }
- secp256k1_scalar_set_b32(&sec, privnonce32, &overflow);
- if (overflow || secp256k1_scalar_is_zero(&sec)) {
- continue;
- }
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec);
- secp256k1_ge_set_gej(&Q, &Qj);
-
- secp256k1_pubkey_save(pubnonce, &Q);
- break;
- } while(1);
-
- secp256k1_scalar_clear(&sec);
- if (!ret) {
- memset(pubnonce, 0, sizeof(*pubnonce));
- }
- return ret;
-}
-
-int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) {
- int overflow = 0;
- secp256k1_scalar sec, non;
- secp256k1_ge pubnon;
- VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
- ARG_CHECK(msg32 != NULL);
- ARG_CHECK(sig64 != NULL);
- ARG_CHECK(sec32 != NULL);
- ARG_CHECK(secnonce32 != NULL);
- ARG_CHECK(pubnonce_others != NULL);
-
- secp256k1_scalar_set_b32(&sec, sec32, &overflow);
- if (overflow || secp256k1_scalar_is_zero(&sec)) {
- return -1;
- }
- secp256k1_scalar_set_b32(&non, secnonce32, &overflow);
- if (overflow || secp256k1_scalar_is_zero(&non)) {
- return -1;
- }
- secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others);
- return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32);
-}
-
-int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, size_t n) {
- ARG_CHECK(sig64 != NULL);
- ARG_CHECK(n >= 1);
- ARG_CHECK(sig64sin != NULL);
- return secp256k1_schnorr_sig_combine(sig64, n, sig64sin);
-}
-
-#endif
diff --git a/src/secp256k1/src/modules/schnorr/schnorr.h b/src/secp256k1/src/modules/schnorr/schnorr.h
deleted file mode 100644
index de18147bd5..0000000000
--- a/src/secp256k1/src/modules/schnorr/schnorr.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/***********************************************************************
- * Copyright (c) 2014-2015 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or http://www.opensource.org/licenses/mit-license.php. *
- ***********************************************************************/
-
-#ifndef _SECP256K1_MODULE_SCHNORR_H_
-#define _SECP256K1_MODULE_SCHNORR_H_
-
-#include "scalar.h"
-#include "group.h"
-
-typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32);
-
-static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
-static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
-static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32);
-static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins);
-
-#endif
diff --git a/src/secp256k1/src/modules/schnorr/schnorr_impl.h b/src/secp256k1/src/modules/schnorr/schnorr_impl.h
deleted file mode 100644
index e13ab6db7c..0000000000
--- a/src/secp256k1/src/modules/schnorr/schnorr_impl.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/***********************************************************************
- * Copyright (c) 2014-2015 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or http://www.opensource.org/licenses/mit-license.php. *
- ***********************************************************************/
-
-#ifndef _SECP256K1_SCHNORR_IMPL_H_
-#define _SECP256K1_SCHNORR_IMPL_H_
-
-#include <string.h>
-
-#include "schnorr.h"
-#include "num.h"
-#include "field.h"
-#include "group.h"
-#include "ecmult.h"
-#include "ecmult_gen.h"
-
-/**
- * Custom Schnorr-based signature scheme. They support multiparty signing, public key
- * recovery and batch validation.
- *
- * Rationale for verifying R's y coordinate:
- * In order to support batch validation and public key recovery, the full R point must
- * be known to verifiers, rather than just its x coordinate. In order to not risk
- * being more strict in batch validation than normal validation, validators must be
- * required to reject signatures with incorrect y coordinate. This is only possible
- * by including a (relatively slow) field inverse, or a field square root. However,
- * batch validation offers potentially much higher benefits than this cost.
- *
- * Rationale for having an implicit y coordinate oddness:
- * If we commit to having the full R point known to verifiers, there are two mechanism.
- * Either include its oddness in the signature, or give it an implicit fixed value.
- * As the R y coordinate can be flipped by a simple negation of the nonce, we choose the
- * latter, as it comes with nearly zero impact on signing or validation performance, and
- * saves a byte in the signature.
- *
- * Signing:
- * Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0)
- *
- * Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce).
- * Compute 32-byte r, the serialization of R's x coordinate.
- * Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order.
- * Compute scalar s = k - h * x.
- * The signature is (r, s).
- *
- *
- * Verification:
- * Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s)
- *
- * Signature is invalid if s >= order.
- * Signature is invalid if r >= p.
- * Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order.
- * Option 1 (faster for single verification):
- * Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd.
- * Signature is valid if the serialization of R's x coordinate equals r.
- * Option 2 (allows batch validation and pubkey recovery):
- * Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve.
- * Signature is valid if R + h * Q + s * G == 0.
- */
-
-static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
- secp256k1_gej Rj;
- secp256k1_ge Ra;
- unsigned char h32[32];
- secp256k1_scalar h, s;
- int overflow;
- secp256k1_scalar n;
-
- if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) {
- return 0;
- }
- n = *nonce;
-
- secp256k1_ecmult_gen(ctx, &Rj, &n);
- if (pubnonce != NULL) {
- secp256k1_gej_add_ge(&Rj, &Rj, pubnonce);
- }
- secp256k1_ge_set_gej(&Ra, &Rj);
- secp256k1_fe_normalize(&Ra.y);
- if (secp256k1_fe_is_odd(&Ra.y)) {
- /* R's y coordinate is odd, which is not allowed (see rationale above).
- Force it to be even by negating the nonce. Note that this even works
- for multiparty signing, as the R point is known to all participants,
- which can all decide to flip the sign in unison, resulting in the
- overall R point to be negated too. */
- secp256k1_scalar_negate(&n, &n);
- }
- secp256k1_fe_normalize(&Ra.x);
- secp256k1_fe_get_b32(sig64, &Ra.x);
- hash(h32, sig64, msg32);
- overflow = 0;
- secp256k1_scalar_set_b32(&h, h32, &overflow);
- if (overflow || secp256k1_scalar_is_zero(&h)) {
- secp256k1_scalar_clear(&n);
- return 0;
- }
- secp256k1_scalar_mul(&s, &h, key);
- secp256k1_scalar_negate(&s, &s);
- secp256k1_scalar_add(&s, &s, &n);
- secp256k1_scalar_clear(&n);
- secp256k1_scalar_get_b32(sig64 + 32, &s);
- return 1;
-}
-
-static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
- secp256k1_gej Qj, Rj;
- secp256k1_ge Ra;
- secp256k1_fe Rx;
- secp256k1_scalar h, s;
- unsigned char hh[32];
- int overflow;
-
- if (secp256k1_ge_is_infinity(pubkey)) {
- return 0;
- }
- hash(hh, sig64, msg32);
- overflow = 0;
- secp256k1_scalar_set_b32(&h, hh, &overflow);
- if (overflow || secp256k1_scalar_is_zero(&h)) {
- return 0;
- }
- overflow = 0;
- secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
- if (overflow) {
- return 0;
- }
- if (!secp256k1_fe_set_b32(&Rx, sig64)) {
- return 0;
- }
- secp256k1_gej_set_ge(&Qj, pubkey);
- secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s);
- if (secp256k1_gej_is_infinity(&Rj)) {
- return 0;
- }
- secp256k1_ge_set_gej_var(&Ra, &Rj);
- secp256k1_fe_normalize_var(&Ra.y);
- if (secp256k1_fe_is_odd(&Ra.y)) {
- return 0;
- }
- return secp256k1_fe_equal_var(&Rx, &Ra.x);
-}
-
-static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) {
- secp256k1_gej Qj, Rj;
- secp256k1_ge Ra;
- secp256k1_fe Rx;
- secp256k1_scalar h, s;
- unsigned char hh[32];
- int overflow;
-
- hash(hh, sig64, msg32);
- overflow = 0;
- secp256k1_scalar_set_b32(&h, hh, &overflow);
- if (overflow || secp256k1_scalar_is_zero(&h)) {
- return 0;
- }
- overflow = 0;
- secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
- if (overflow) {
- return 0;
- }
- if (!secp256k1_fe_set_b32(&Rx, sig64)) {
- return 0;
- }
- if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) {
- return 0;
- }
- secp256k1_gej_set_ge(&Rj, &Ra);
- secp256k1_scalar_inverse_var(&h, &h);
- secp256k1_scalar_negate(&s, &s);
- secp256k1_scalar_mul(&s, &s, &h);
- secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s);
- if (secp256k1_gej_is_infinity(&Qj)) {
- return 0;
- }
- secp256k1_ge_set_gej(pubkey, &Qj);
- return 1;
-}
-
-static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins) {
- secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
- size_t i;
- for (i = 0; i < n; i++) {
- secp256k1_scalar si;
- int overflow;
- secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow);
- if (overflow) {
- return -1;
- }
- if (i) {
- if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) {
- return -1;
- }
- }
- secp256k1_scalar_add(&s, &s, &si);
- }
- if (secp256k1_scalar_is_zero(&s)) {
- return 0;
- }
- memcpy(sig64, sig64ins[0], 32);
- secp256k1_scalar_get_b32(sig64 + 32, &s);
- secp256k1_scalar_clear(&s);
- return 1;
-}
-
-#endif
diff --git a/src/secp256k1/src/modules/schnorr/tests_impl.h b/src/secp256k1/src/modules/schnorr/tests_impl.h
deleted file mode 100644
index 5bd14a03e3..0000000000
--- a/src/secp256k1/src/modules/schnorr/tests_impl.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/**********************************************************************
- * Copyright (c) 2014-2015 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
- **********************************************************************/
-
-#ifndef SECP256K1_MODULE_SCHNORR_TESTS
-#define SECP256K1_MODULE_SCHNORR_TESTS
-
-#include "include/secp256k1_schnorr.h"
-
-void test_schnorr_end_to_end(void) {
- unsigned char privkey[32];
- unsigned char message[32];
- unsigned char schnorr_signature[64];
- secp256k1_pubkey pubkey, recpubkey;
-
- /* Generate a random key and message. */
- {
- secp256k1_scalar key;
- random_scalar_order_test(&key);
- secp256k1_scalar_get_b32(privkey, &key);
- secp256k1_rand256_test(message);
- }
-
- /* Construct and verify corresponding public key. */
- CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
- CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
-
- /* Schnorr sign. */
- CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1);
- CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1);
- CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1);
- CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
- /* Destroy signature and verify again. */
- schnorr_signature[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255);
- CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0);
- CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 ||
- memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
-}
-
-/** Horribly broken hash function. Do not use for anything but tests. */
-void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) {
- int i;
- for (i = 0; i < 32; i++) {
- h32[i] = r32[i] ^ msg32[i];
- }
-}
-
-void test_schnorr_sign_verify(void) {
- unsigned char msg32[32];
- unsigned char sig64[3][64];
- secp256k1_gej pubkeyj[3];
- secp256k1_ge pubkey[3];
- secp256k1_scalar nonce[3], key[3];
- int i = 0;
- int k;
-
- secp256k1_rand256_test(msg32);
-
- for (k = 0; k < 3; k++) {
- random_scalar_order_test(&key[k]);
-
- do {
- random_scalar_order_test(&nonce[k]);
- if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) {
- break;
- }
- } while(1);
-
- secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]);
- secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]);
- CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32));
-
- for (i = 0; i < 4; i++) {
- int pos = secp256k1_rand_bits(6);
- int mod = 1 + secp256k1_rand_int(255);
- sig64[k][pos] ^= mod;
- CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0);
- sig64[k][pos] ^= mod;
- }
- }
-}
-
-void test_schnorr_threshold(void) {
- unsigned char msg[32];
- unsigned char sec[5][32];
- secp256k1_pubkey pub[5];
- unsigned char nonce[5][32];
- secp256k1_pubkey pubnonce[5];
- unsigned char sig[5][64];
- const unsigned char* sigs[5];
- unsigned char allsig[64];
- const secp256k1_pubkey* pubs[5];
- secp256k1_pubkey allpub;
- int n, i;
- int damage;
- int ret = 0;
-
- damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0;
- secp256k1_rand256_test(msg);
- n = 2 + secp256k1_rand_int(4);
- for (i = 0; i < n; i++) {
- do {
- secp256k1_rand256_test(sec[i]);
- } while (!secp256k1_ec_seckey_verify(ctx, sec[i]));
- CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i]));
- CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL));
- pubs[i] = &pub[i];
- }
- if (damage == 1) {
- nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
- } else if (damage == 2) {
- sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
- }
- for (i = 0; i < n; i++) {
- secp256k1_pubkey allpubnonce;
- const secp256k1_pubkey *pubnonces[4];
- int j;
- for (j = 0; j < i; j++) {
- pubnonces[j] = &pubnonce[j];
- }
- for (j = i + 1; j < n; j++) {
- pubnonces[j - 1] = &pubnonce[j];
- }
- CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1));
- ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1;
- sigs[i] = sig[i];
- }
- if (damage == 3) {
- sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255);
- }
- ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2;
- if ((ret & 1) == 0) {
- ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4;
- }
- if (damage == 4) {
- allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255);
- }
- if ((ret & 7) == 0) {
- ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8;
- }
- CHECK((ret == 0) == (damage == 0));
-}
-
-void test_schnorr_recovery(void) {
- unsigned char msg32[32];
- unsigned char sig64[64];
- secp256k1_ge Q;
-
- secp256k1_rand256_test(msg32);
- secp256k1_rand256_test(sig64);
- secp256k1_rand256_test(sig64 + 32);
- if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) {
- CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1);
- }
-}
-
-void run_schnorr_tests(void) {
- int i;
- for (i = 0; i < 32*count; i++) {
- test_schnorr_end_to_end();
- }
- for (i = 0; i < 32 * count; i++) {
- test_schnorr_sign_verify();
- }
- for (i = 0; i < 16 * count; i++) {
- test_schnorr_recovery();
- }
- for (i = 0; i < 10 * count; i++) {
- test_schnorr_threshold();
- }
-}
-
-#endif
diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h
index ebfa71eb44..7bb9c5be8c 100644
--- a/src/secp256k1/src/num.h
+++ b/src/secp256k1/src/num.h
@@ -32,6 +32,9 @@ static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsi
/** Compute a modular inverse. The input must be less than the modulus. */
static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m);
+/** Compute the jacobi symbol (a|b). b must be positive and odd. */
+static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b);
+
/** Compare the absolute value of two numbers. */
static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b);
@@ -57,6 +60,9 @@ static void secp256k1_num_shift(secp256k1_num *r, int bits);
/** Check whether a number is zero. */
static int secp256k1_num_is_zero(const secp256k1_num *a);
+/** Check whether a number is one. */
+static int secp256k1_num_is_one(const secp256k1_num *a);
+
/** Check whether a number is strictly negative. */
static int secp256k1_num_is_neg(const secp256k1_num *a);
diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h
index 7b6a89719a..3a46495eea 100644
--- a/src/secp256k1/src/num_gmp_impl.h
+++ b/src/secp256k1/src/num_gmp_impl.h
@@ -144,6 +144,32 @@ static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a,
memset(v, 0, sizeof(v));
}
+static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) {
+ int ret;
+ mpz_t ga, gb;
+ secp256k1_num_sanity(a);
+ secp256k1_num_sanity(b);
+ VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1));
+
+ mpz_inits(ga, gb, NULL);
+
+ mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data);
+ mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data);
+ if (a->neg) {
+ mpz_neg(ga, ga);
+ }
+
+ ret = mpz_jacobi(ga, gb);
+
+ mpz_clears(ga, gb, NULL);
+
+ return ret;
+}
+
+static int secp256k1_num_is_one(const secp256k1_num *a) {
+ return (a->limbs == 1 && a->data[0] == 1);
+}
+
static int secp256k1_num_is_zero(const secp256k1_num *a) {
return (a->limbs == 1 && a->data[0] == 0);
}
diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h
index b590ccd6dd..27e9d8375e 100644
--- a/src/secp256k1/src/scalar.h
+++ b/src/secp256k1/src/scalar.h
@@ -13,7 +13,9 @@
#include "libsecp256k1-config.h"
#endif
-#if defined(USE_SCALAR_4X64)
+#if defined(EXHAUSTIVE_TEST_ORDER)
+#include "scalar_low.h"
+#elif defined(USE_SCALAR_4X64)
#include "scalar_4x64.h"
#elif defined(USE_SCALAR_8X32)
#include "scalar_8x32.h"
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index aa2703dd23..56e7bd82af 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -282,8 +282,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"movq 56(%%rsi), %%r14\n"
/* Initialize r8,r9,r10 */
"movq 0(%%rsi), %%r8\n"
- "movq $0, %%r9\n"
- "movq $0, %%r10\n"
+ "xorq %%r9, %%r9\n"
+ "xorq %%r10, %%r10\n"
/* (r8,r9) += n0 * c0 */
"movq %8, %%rax\n"
"mulq %%r11\n"
@@ -291,7 +291,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"adcq %%rdx, %%r9\n"
/* extract m0 */
"movq %%r8, %q0\n"
- "movq $0, %%r8\n"
+ "xorq %%r8, %%r8\n"
/* (r9,r10) += l1 */
"addq 8(%%rsi), %%r9\n"
"adcq $0, %%r10\n"
@@ -309,7 +309,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"adcq $0, %%r8\n"
/* extract m1 */
"movq %%r9, %q1\n"
- "movq $0, %%r9\n"
+ "xorq %%r9, %%r9\n"
/* (r10,r8,r9) += l2 */
"addq 16(%%rsi), %%r10\n"
"adcq $0, %%r8\n"
@@ -332,7 +332,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"adcq $0, %%r9\n"
/* extract m2 */
"movq %%r10, %q2\n"
- "movq $0, %%r10\n"
+ "xorq %%r10, %%r10\n"
/* (r8,r9,r10) += l3 */
"addq 24(%%rsi), %%r8\n"
"adcq $0, %%r9\n"
@@ -355,7 +355,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"adcq $0, %%r10\n"
/* extract m3 */
"movq %%r8, %q3\n"
- "movq $0, %%r8\n"
+ "xorq %%r8, %%r8\n"
/* (r9,r10,r8) += n3 * c1 */
"movq %9, %%rax\n"
"mulq %%r14\n"
@@ -387,8 +387,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"movq %q11, %%r13\n"
/* Initialize (r8,r9,r10) */
"movq %q5, %%r8\n"
- "movq $0, %%r9\n"
- "movq $0, %%r10\n"
+ "xorq %%r9, %%r9\n"
+ "xorq %%r10, %%r10\n"
/* (r8,r9) += m4 * c0 */
"movq %12, %%rax\n"
"mulq %%r11\n"
@@ -396,7 +396,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"adcq %%rdx, %%r9\n"
/* extract p0 */
"movq %%r8, %q0\n"
- "movq $0, %%r8\n"
+ "xorq %%r8, %%r8\n"
/* (r9,r10) += m1 */
"addq %q6, %%r9\n"
"adcq $0, %%r10\n"
@@ -414,7 +414,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"adcq $0, %%r8\n"
/* extract p1 */
"movq %%r9, %q1\n"
- "movq $0, %%r9\n"
+ "xorq %%r9, %%r9\n"
/* (r10,r8,r9) += m2 */
"addq %q7, %%r10\n"
"adcq $0, %%r8\n"
@@ -472,7 +472,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"movq %%rax, 0(%q6)\n"
/* Move to (r8,r9) */
"movq %%rdx, %%r8\n"
- "movq $0, %%r9\n"
+ "xorq %%r9, %%r9\n"
/* (r8,r9) += p1 */
"addq %q2, %%r8\n"
"adcq $0, %%r9\n"
@@ -483,7 +483,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"adcq %%rdx, %%r9\n"
/* Extract r1 */
"movq %%r8, 8(%q6)\n"
- "movq $0, %%r8\n"
+ "xorq %%r8, %%r8\n"
/* (r9,r8) += p4 */
"addq %%r10, %%r9\n"
"adcq $0, %%r8\n"
@@ -492,7 +492,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"adcq $0, %%r8\n"
/* Extract r2 */
"movq %%r9, 16(%q6)\n"
- "movq $0, %%r9\n"
+ "xorq %%r9, %%r9\n"
/* (r8,r9) += p3 */
"addq %q4, %%r8\n"
"adcq $0, %%r9\n"
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index 88ea97de86..f5b2376407 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -7,8 +7,6 @@
#ifndef _SECP256K1_SCALAR_IMPL_H_
#define _SECP256K1_SCALAR_IMPL_H_
-#include <string.h>
-
#include "group.h"
#include "scalar.h"
@@ -16,7 +14,9 @@
#include "libsecp256k1-config.h"
#endif
-#if defined(USE_SCALAR_4X64)
+#if defined(EXHAUSTIVE_TEST_ORDER)
+#include "scalar_low_impl.h"
+#elif defined(USE_SCALAR_4X64)
#include "scalar_4x64_impl.h"
#elif defined(USE_SCALAR_8X32)
#include "scalar_8x32_impl.h"
@@ -33,17 +33,37 @@ static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a
/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */
static void secp256k1_scalar_order_get_num(secp256k1_num *r) {
+#if defined(EXHAUSTIVE_TEST_ORDER)
+ static const unsigned char order[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,EXHAUSTIVE_TEST_ORDER
+ };
+#else
static const unsigned char order[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
};
+#endif
secp256k1_num_set_bin(r, order, 32);
}
#endif
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {
+#if defined(EXHAUSTIVE_TEST_ORDER)
+ int i;
+ *r = 0;
+ for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++)
+ if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1)
+ *r = i;
+ /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus
+ * have a composite group order; fix it in exhaustive_tests.c). */
+ VERIFY_CHECK(*r != 0);
+}
+#else
secp256k1_scalar *t;
int i;
/* First compute x ^ (2^N - 1) for some values of N. */
@@ -235,9 +255,9 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
}
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
- /* d[0] is present and is the lowest word for all representations */
return !(a->d[0] & 1);
}
+#endif
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
#if defined(USE_SCALAR_INV_BUILTIN)
@@ -261,6 +281,18 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc
}
#ifdef USE_ENDOMORPHISM
+#if defined(EXHAUSTIVE_TEST_ORDER)
+/**
+ * Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the
+ * full case we don't bother making k1 and k2 be small, we just want them to be
+ * nontrivial to get full test coverage for the exhaustive tests. We therefore
+ * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda.
+ */
+static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
+ *r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER;
+ *r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER;
+}
+#else
/**
* The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where
* lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
@@ -333,5 +365,6 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
secp256k1_scalar_add(r1, r1, a);
}
#endif
+#endif
#endif
diff --git a/src/secp256k1/src/scalar_low.h b/src/secp256k1/src/scalar_low.h
new file mode 100644
index 0000000000..5574c44c7a
--- /dev/null
+++ b/src/secp256k1/src/scalar_low.h
@@ -0,0 +1,15 @@
+/**********************************************************************
+ * Copyright (c) 2015 Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_SCALAR_REPR_
+#define _SECP256K1_SCALAR_REPR_
+
+#include <stdint.h>
+
+/** A scalar modulo the group order of the secp256k1 curve. */
+typedef uint32_t secp256k1_scalar;
+
+#endif
diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h
new file mode 100644
index 0000000000..4f94441f49
--- /dev/null
+++ b/src/secp256k1/src/scalar_low_impl.h
@@ -0,0 +1,114 @@
+/**********************************************************************
+ * Copyright (c) 2015 Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
+#define _SECP256K1_SCALAR_REPR_IMPL_H_
+
+#include "scalar.h"
+
+#include <string.h>
+
+SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
+ return !(*a & 1);
+}
+
+SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; }
+SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; }
+
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
+ if (offset < 32)
+ return ((*a >> offset) & ((((uint32_t)1) << count) - 1));
+ else
+ return 0;
+}
+
+SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
+ return secp256k1_scalar_get_bits(a, offset, count);
+}
+
+SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; }
+
+static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
+ *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER;
+ return *r < *b;
+}
+
+static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
+ if (flag && bit < 32)
+ *r += (1 << bit);
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
+#endif
+}
+
+static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
+ const int base = 0x100 % EXHAUSTIVE_TEST_ORDER;
+ int i;
+ *r = 0;
+ for (i = 0; i < 32; i++) {
+ *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER;
+ }
+ /* just deny overflow, it basically always happens */
+ if (overflow) *overflow = 0;
+}
+
+static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
+ memset(bin, 0, 32);
+ bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
+}
+
+SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
+ return *a == 0;
+}
+
+static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
+ if (*a == 0) {
+ *r = 0;
+ } else {
+ *r = EXHAUSTIVE_TEST_ORDER - *a;
+ }
+}
+
+SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
+ return *a == 1;
+}
+
+static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
+ return *a > EXHAUSTIVE_TEST_ORDER / 2;
+}
+
+static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
+ if (flag) secp256k1_scalar_negate(r, r);
+ return flag ? -1 : 1;
+}
+
+static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
+ *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;
+}
+
+static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
+ int ret;
+ VERIFY_CHECK(n > 0);
+ VERIFY_CHECK(n < 16);
+ ret = *r & ((1 << n) - 1);
+ *r >>= n;
+ return ret;
+}
+
+static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
+ *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER;
+}
+
+static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
+ *r1 = *a;
+ *r2 = 0;
+}
+
+SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
+ return *a == *b;
+}
+
+#endif
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 62d192baeb..fb8b882faa 100644..100755
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -4,8 +4,6 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#define SECP256K1_BUILD (1)
-
#include "include/secp256k1.h"
#include "util.h"
@@ -152,7 +150,6 @@ static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {
secp256k1_ge Q;
- (void)ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pubkey != NULL);
memset(pubkey, 0, sizeof(*pubkey));
@@ -170,7 +167,6 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o
size_t len;
int ret = 0;
- (void)ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(outputlen != NULL);
ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65));
@@ -216,7 +212,7 @@ static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const
int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
secp256k1_scalar r, s;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(input != NULL);
@@ -234,7 +230,7 @@ int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp25
int ret = 1;
int overflow = 0;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(input64 != NULL);
@@ -253,7 +249,7 @@ int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp25
int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) {
secp256k1_scalar r, s;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output != NULL);
ARG_CHECK(outputlen != NULL);
ARG_CHECK(sig != NULL);
@@ -265,7 +261,7 @@ int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsign
int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) {
secp256k1_scalar r, s;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output64 != NULL);
ARG_CHECK(sig != NULL);
@@ -363,16 +359,15 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
/* Fail if the secret key is invalid. */
if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
+ unsigned char nonce32[32];
unsigned int count = 0;
secp256k1_scalar_set_b32(&msg, msg32, NULL);
while (1) {
- unsigned char nonce32[32];
ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
if (!ret) {
break;
}
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
- memset(nonce32, 0, 32);
if (!overflow && !secp256k1_scalar_is_zero(&non)) {
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) {
break;
@@ -380,6 +375,7 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature
}
count++;
}
+ memset(nonce32, 0, 32);
secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non);
secp256k1_scalar_clear(&sec);
@@ -398,7 +394,6 @@ int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char
int overflow;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
- (void)ctx;
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
ret = !overflow && !secp256k1_scalar_is_zero(&sec);
@@ -437,7 +432,6 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
ARG_CHECK(tweak != NULL);
- (void)ctx;
secp256k1_scalar_set_b32(&term, tweak, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
@@ -485,7 +479,6 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
ARG_CHECK(tweak != NULL);
- (void)ctx;
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 687a5f2fdd..9ae7d30281 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -473,6 +473,8 @@ void test_num_negate(void) {
}
void test_num_add_sub(void) {
+ int i;
+ secp256k1_scalar s;
secp256k1_num n1;
secp256k1_num n2;
secp256k1_num n1p2, n2p1, n1m2, n2m1;
@@ -498,6 +500,110 @@ void test_num_add_sub(void) {
CHECK(!secp256k1_num_eq(&n2p1, &n1));
secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */
CHECK(secp256k1_num_eq(&n2p1, &n1));
+
+ /* check is_one */
+ secp256k1_scalar_set_int(&s, 1);
+ secp256k1_scalar_get_num(&n1, &s);
+ CHECK(secp256k1_num_is_one(&n1));
+ /* check that 2^n + 1 is never 1 */
+ secp256k1_scalar_get_num(&n2, &s);
+ for (i = 0; i < 250; ++i) {
+ secp256k1_num_add(&n1, &n1, &n1); /* n1 *= 2 */
+ secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */
+ CHECK(!secp256k1_num_is_one(&n1p2));
+ }
+}
+
+void test_num_mod(void) {
+ int i;
+ secp256k1_scalar s;
+ secp256k1_num order, n;
+
+ /* check that 0 mod anything is 0 */
+ random_scalar_order_test(&s);
+ secp256k1_scalar_get_num(&order, &s);
+ secp256k1_scalar_set_int(&s, 0);
+ secp256k1_scalar_get_num(&n, &s);
+ secp256k1_num_mod(&n, &order);
+ CHECK(secp256k1_num_is_zero(&n));
+
+ /* check that anything mod 1 is 0 */
+ secp256k1_scalar_set_int(&s, 1);
+ secp256k1_scalar_get_num(&order, &s);
+ secp256k1_scalar_get_num(&n, &s);
+ secp256k1_num_mod(&n, &order);
+ CHECK(secp256k1_num_is_zero(&n));
+
+ /* check that increasing the number past 2^256 does not break this */
+ random_scalar_order_test(&s);
+ secp256k1_scalar_get_num(&n, &s);
+ /* multiply by 2^8, which'll test this case with high probability */
+ for (i = 0; i < 8; ++i) {
+ secp256k1_num_add(&n, &n, &n);
+ }
+ secp256k1_num_mod(&n, &order);
+ CHECK(secp256k1_num_is_zero(&n));
+}
+
+void test_num_jacobi(void) {
+ secp256k1_scalar sqr;
+ secp256k1_scalar small;
+ secp256k1_scalar five; /* five is not a quadratic residue */
+ secp256k1_num order, n;
+ int i;
+ /* squares mod 5 are 1, 4 */
+ const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 };
+
+ /* check some small values with 5 as the order */
+ secp256k1_scalar_set_int(&five, 5);
+ secp256k1_scalar_get_num(&order, &five);
+ for (i = 0; i < 10; ++i) {
+ secp256k1_scalar_set_int(&small, i);
+ secp256k1_scalar_get_num(&n, &small);
+ CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]);
+ }
+
+ /** test large values with 5 as group order */
+ secp256k1_scalar_get_num(&order, &five);
+ /* we first need a scalar which is not a multiple of 5 */
+ do {
+ secp256k1_num fiven;
+ random_scalar_order_test(&sqr);
+ secp256k1_scalar_get_num(&fiven, &five);
+ secp256k1_scalar_get_num(&n, &sqr);
+ secp256k1_num_mod(&n, &fiven);
+ } while (secp256k1_num_is_zero(&n));
+ /* next force it to be a residue. 2 is a nonresidue mod 5 so we can
+ * just multiply by two, i.e. add the number to itself */
+ if (secp256k1_num_jacobi(&n, &order) == -1) {
+ secp256k1_num_add(&n, &n, &n);
+ }
+
+ /* test residue */
+ CHECK(secp256k1_num_jacobi(&n, &order) == 1);
+ /* test nonresidue */
+ secp256k1_num_add(&n, &n, &n);
+ CHECK(secp256k1_num_jacobi(&n, &order) == -1);
+
+ /** test with secp group order as order */
+ secp256k1_scalar_order_get_num(&order);
+ random_scalar_order_test(&sqr);
+ secp256k1_scalar_sqr(&sqr, &sqr);
+ /* test residue */
+ secp256k1_scalar_get_num(&n, &sqr);
+ CHECK(secp256k1_num_jacobi(&n, &order) == 1);
+ /* test nonresidue */
+ secp256k1_scalar_mul(&sqr, &sqr, &five);
+ secp256k1_scalar_get_num(&n, &sqr);
+ CHECK(secp256k1_num_jacobi(&n, &order) == -1);
+ /* test multiple of the order*/
+ CHECK(secp256k1_num_jacobi(&order, &order) == 0);
+
+ /* check one less than the order */
+ secp256k1_scalar_set_int(&small, 1);
+ secp256k1_scalar_get_num(&n, &small);
+ secp256k1_num_sub(&n, &order, &n);
+ CHECK(secp256k1_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */
}
void run_num_smalltests(void) {
@@ -505,6 +611,8 @@ void run_num_smalltests(void) {
for (i = 0; i < 100*count; i++) {
test_num_negate();
test_num_add_sub();
+ test_num_mod();
+ test_num_jacobi();
}
}
#endif
@@ -689,6 +797,10 @@ void scalar_test(void) {
secp256k1_scalar_inverse(&inv, &inv);
/* Inverting one must result in one. */
CHECK(secp256k1_scalar_is_one(&inv));
+#ifndef USE_NUM_NONE
+ secp256k1_scalar_get_num(&invnum, &inv);
+ CHECK(secp256k1_num_is_one(&invnum));
+#endif
}
}
@@ -855,7 +967,7 @@ void run_scalar_tests(void) {
secp256k1_scalar zzv;
#endif
int overflow;
- unsigned char chal[32][2][32] = {
+ unsigned char chal[33][2][32] = {
{{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
@@ -1111,9 +1223,17 @@ void run_scalar_tests(void) {
{0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}
+ 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}},
+ {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb,
+ 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03},
+ {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb,
+ 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}}
};
- unsigned char res[32][2][32] = {
+ unsigned char res[33][2][32] = {
{{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9,
0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1,
0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6,
@@ -1369,10 +1489,18 @@ void run_scalar_tests(void) {
{0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2,
0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38,
0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34,
- 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}
+ 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}},
+ {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34,
+ 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13,
+ 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,
+ 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5},
+ {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34,
+ 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13,
+ 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,
+ 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}}
};
secp256k1_scalar_set_int(&one, 1);
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < 33; i++) {
secp256k1_scalar_set_b32(&x, chal[i][0], &overflow);
CHECK(!overflow);
secp256k1_scalar_set_b32(&y, chal[i][1], &overflow);
@@ -1446,7 +1574,7 @@ void random_fe_non_zero(secp256k1_fe *nz) {
void random_fe_non_square(secp256k1_fe *ns) {
secp256k1_fe r;
random_fe_non_zero(ns);
- if (secp256k1_fe_sqrt_var(&r, ns)) {
+ if (secp256k1_fe_sqrt(&r, ns)) {
secp256k1_fe_negate(ns, ns, 1);
}
}
@@ -1605,18 +1733,18 @@ void run_field_inv_all_var(void) {
secp256k1_fe x[16], xi[16], xii[16];
int i;
/* Check it's safe to call for 0 elements */
- secp256k1_fe_inv_all_var(0, xi, x);
+ secp256k1_fe_inv_all_var(xi, x, 0);
for (i = 0; i < count; i++) {
size_t j;
size_t len = secp256k1_rand_int(15) + 1;
for (j = 0; j < len; j++) {
random_fe_non_zero(&x[j]);
}
- secp256k1_fe_inv_all_var(len, xi, x);
+ secp256k1_fe_inv_all_var(xi, x, len);
for (j = 0; j < len; j++) {
CHECK(check_fe_inverse(&x[j], &xi[j]));
}
- secp256k1_fe_inv_all_var(len, xii, xi);
+ secp256k1_fe_inv_all_var(xii, xi, len);
for (j = 0; j < len; j++) {
CHECK(check_fe_equal(&x[j], &xii[j]));
}
@@ -1641,7 +1769,7 @@ void run_sqr(void) {
void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) {
secp256k1_fe r1, r2;
- int v = secp256k1_fe_sqrt_var(&r1, a);
+ int v = secp256k1_fe_sqrt(&r1, a);
CHECK((v == 0) == (k == NULL));
if (k != NULL) {
@@ -1802,7 +1930,7 @@ void test_ge(void) {
zs[i] = gej[i].z;
}
}
- secp256k1_fe_inv_all_var(4 * runs + 1, zinv, zs);
+ secp256k1_fe_inv_all_var(zinv, zs, 4 * runs + 1);
free(zs);
}
@@ -1922,8 +2050,8 @@ void test_ge(void) {
secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z);
}
}
- secp256k1_ge_set_table_gej_var(4 * runs + 1, ge_set_table, gej, zr);
- secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej, &ctx->error_callback);
+ secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1);
+ secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback);
for (i = 0; i < 4 * runs + 1; i++) {
secp256k1_fe s;
random_fe_non_zero(&s);
@@ -1951,8 +2079,8 @@ void test_add_neg_y_diff_x(void) {
* of the sum to be wrong (since infinity has no xy coordinates).
* HOWEVER, if the x-coordinates are different, infinity is the
* wrong answer, and such degeneracies are exposed. This is the
- * root of https://github.com/bitcoin/secp256k1/issues/257 which
- * this test is a regression test for.
+ * root of https://github.com/bitcoin-core/secp256k1/issues/257
+ * which this test is a regression test for.
*
* These points were generated in sage as
* # secp256k1 params
@@ -2051,15 +2179,16 @@ void run_ec_combine(void) {
void test_group_decompress(const secp256k1_fe* x) {
/* The input itself, normalized. */
secp256k1_fe fex = *x;
- secp256k1_fe tmp;
+ secp256k1_fe fez;
/* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */
secp256k1_ge ge_quad, ge_even, ge_odd;
+ secp256k1_gej gej_quad;
/* Return values of the above calls. */
int res_quad, res_even, res_odd;
secp256k1_fe_normalize_var(&fex);
- res_quad = secp256k1_ge_set_xquad_var(&ge_quad, &fex);
+ res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex);
res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0);
res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1);
@@ -2085,13 +2214,29 @@ void test_group_decompress(const secp256k1_fe* x) {
CHECK(secp256k1_fe_equal_var(&ge_odd.x, x));
/* Check that the Y coordinate result in ge_quad is a square. */
- CHECK(secp256k1_fe_sqrt_var(&tmp, &ge_quad.y));
- secp256k1_fe_sqr(&tmp, &tmp);
- CHECK(secp256k1_fe_equal_var(&tmp, &ge_quad.y));
+ CHECK(secp256k1_fe_is_quad_var(&ge_quad.y));
/* Check odd/even Y in ge_odd, ge_even. */
CHECK(secp256k1_fe_is_odd(&ge_odd.y));
CHECK(!secp256k1_fe_is_odd(&ge_even.y));
+
+ /* Check secp256k1_gej_has_quad_y_var. */
+ secp256k1_gej_set_ge(&gej_quad, &ge_quad);
+ CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
+ do {
+ random_fe_test(&fez);
+ } while (secp256k1_fe_is_zero(&fez));
+ secp256k1_gej_rescale(&gej_quad, &fez);
+ CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
+ secp256k1_gej_neg(&gej_quad, &gej_quad);
+ CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad));
+ do {
+ random_fe_test(&fez);
+ } while (secp256k1_fe_is_zero(&fez));
+ secp256k1_gej_rescale(&gej_quad, &fez);
+ CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad));
+ secp256k1_gej_neg(&gej_quad, &gej_quad);
+ CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
}
}
@@ -2383,9 +2528,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
secp256k1_scalar x, shift;
int wnaf[256] = {0};
int i;
-#ifdef USE_ENDOMORPHISM
int skew;
-#endif
secp256k1_scalar num = *number;
secp256k1_scalar_set_int(&x, 0);
@@ -2395,10 +2538,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
for (i = 0; i < 16; ++i) {
secp256k1_scalar_shr_int(&num, 8);
}
- skew = secp256k1_wnaf_const(wnaf, num, w);
-#else
- secp256k1_wnaf_const(wnaf, num, w);
#endif
+ skew = secp256k1_wnaf_const(wnaf, num, w);
for (i = WNAF_SIZE(w); i >= 0; --i) {
secp256k1_scalar t;
@@ -2417,10 +2558,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
}
secp256k1_scalar_add(&x, &x, &t);
}
-#ifdef USE_ENDOMORPHISM
- /* Skew num because when encoding 128-bit numbers as odd we use an offset */
+ /* Skew num because when encoding numbers as odd we use an offset */
secp256k1_scalar_cadd_bit(&num, skew == 2, 1);
-#endif
CHECK(secp256k1_scalar_eq(&x, &num));
}
@@ -3484,12 +3623,14 @@ void run_ecdsa_end_to_end(void) {
int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) {
static const unsigned char zeroes[32] = {0};
+#ifdef ENABLE_OPENSSL_TESTS
static const unsigned char max_scalar[32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40
};
+#endif
int ret = 0;
@@ -3607,13 +3748,13 @@ static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) {
static void damage_array(unsigned char *sig, size_t *len) {
int pos;
int action = secp256k1_rand_bits(3);
- if (action < 1) {
+ if (action < 1 && *len > 3) {
/* Delete a byte. */
pos = secp256k1_rand_int(*len);
memmove(sig + pos, sig + pos + 1, *len - pos - 1);
(*len)--;
return;
- } else if (action < 2) {
+ } else if (action < 2 && *len < 2048) {
/* Insert a byte. */
pos = secp256k1_rand_int(1 + *len);
memmove(sig + pos + 1, sig + pos, *len - pos);
@@ -3785,6 +3926,7 @@ void run_ecdsa_der_parse(void) {
int certainly_der = 0;
int certainly_not_der = 0;
random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der);
+ CHECK(buflen <= 2048);
for (j = 0; j < 16; j++) {
int ret = 0;
if (j > 0) {
diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c
new file mode 100644
index 0000000000..bda6ee475c
--- /dev/null
+++ b/src/secp256k1/src/tests_exhaustive.c
@@ -0,0 +1,329 @@
+/***********************************************************************
+ * Copyright (c) 2016 Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#if defined HAVE_CONFIG_H
+#include "libsecp256k1-config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <time.h>
+
+#undef USE_ECMULT_STATIC_PRECOMPUTATION
+
+#ifndef EXHAUSTIVE_TEST_ORDER
+/* see group_impl.h for allowable values */
+#define EXHAUSTIVE_TEST_ORDER 13
+#define EXHAUSTIVE_TEST_LAMBDA 9 /* cube root of 1 mod 13 */
+#endif
+
+#include "include/secp256k1.h"
+#include "group.h"
+#include "secp256k1.c"
+#include "testrand_impl.h"
+
+/** stolen from tests.c */
+void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
+ CHECK(a->infinity == b->infinity);
+ if (a->infinity) {
+ return;
+ }
+ CHECK(secp256k1_fe_equal_var(&a->x, &b->x));
+ CHECK(secp256k1_fe_equal_var(&a->y, &b->y));
+}
+
+void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
+ secp256k1_fe z2s;
+ secp256k1_fe u1, u2, s1, s2;
+ CHECK(a->infinity == b->infinity);
+ if (a->infinity) {
+ return;
+ }
+ /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */
+ secp256k1_fe_sqr(&z2s, &b->z);
+ secp256k1_fe_mul(&u1, &a->x, &z2s);
+ u2 = b->x; secp256k1_fe_normalize_weak(&u2);
+ secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z);
+ s2 = b->y; secp256k1_fe_normalize_weak(&s2);
+ CHECK(secp256k1_fe_equal_var(&u1, &u2));
+ CHECK(secp256k1_fe_equal_var(&s1, &s2));
+}
+
+void random_fe(secp256k1_fe *x) {
+ unsigned char bin[32];
+ do {
+ secp256k1_rand256(bin);
+ if (secp256k1_fe_set_b32(x, bin)) {
+ return;
+ }
+ } while(1);
+}
+/** END stolen from tests.c */
+
+int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,
+ const unsigned char *key32, const unsigned char *algo16,
+ void *data, unsigned int attempt) {
+ secp256k1_scalar s;
+ int *idata = data;
+ (void)msg32;
+ (void)key32;
+ (void)algo16;
+ /* Some nonces cannot be used because they'd cause s and/or r to be zero.
+ * The signing function has retry logic here that just re-calls the nonce
+ * 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)++;
+ }
+ secp256k1_scalar_set_int(&s, *idata);
+ secp256k1_scalar_get_b32(nonce32, &s);
+ return 1;
+}
+
+#ifdef USE_ENDOMORPHISM
+void test_exhaustive_endomorphism(const secp256k1_ge *group, int order) {
+ int i;
+ for (i = 0; i < order; i++) {
+ secp256k1_ge res;
+ secp256k1_ge_mul_lambda(&res, &group[i]);
+ ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res);
+ }
+}
+#endif
+
+void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj, int order) {
+ int i, j;
+
+ /* Sanity-check (and check infinity functions) */
+ CHECK(secp256k1_ge_is_infinity(&group[0]));
+ CHECK(secp256k1_gej_is_infinity(&groupj[0]));
+ for (i = 1; i < order; i++) {
+ CHECK(!secp256k1_ge_is_infinity(&group[i]));
+ CHECK(!secp256k1_gej_is_infinity(&groupj[i]));
+ }
+
+ /* Check all addition formulae */
+ for (j = 0; j < order; j++) {
+ secp256k1_fe fe_inv;
+ secp256k1_fe_inv(&fe_inv, &groupj[j].z);
+ for (i = 0; i < order; i++) {
+ secp256k1_ge zless_gej;
+ secp256k1_gej tmp;
+ /* add_var */
+ secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL);
+ ge_equals_gej(&group[(i + j) % order], &tmp);
+ /* add_ge */
+ if (j > 0) {
+ secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]);
+ ge_equals_gej(&group[(i + j) % order], &tmp);
+ }
+ /* add_ge_var */
+ secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL);
+ ge_equals_gej(&group[(i + j) % order], &tmp);
+ /* add_zinv_var */
+ zless_gej.infinity = groupj[j].infinity;
+ zless_gej.x = groupj[j].x;
+ zless_gej.y = groupj[j].y;
+ secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv);
+ ge_equals_gej(&group[(i + j) % order], &tmp);
+ }
+ }
+
+ /* Check doubling */
+ for (i = 0; i < order; i++) {
+ secp256k1_gej tmp;
+ if (i > 0) {
+ secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL);
+ ge_equals_gej(&group[(2 * i) % order], &tmp);
+ }
+ secp256k1_gej_double_var(&tmp, &groupj[i], NULL);
+ ge_equals_gej(&group[(2 * i) % order], &tmp);
+ }
+
+ /* Check negation */
+ for (i = 1; i < order; i++) {
+ secp256k1_ge tmp;
+ secp256k1_gej tmpj;
+ secp256k1_ge_neg(&tmp, &group[i]);
+ ge_equals_ge(&group[order - i], &tmp);
+ secp256k1_gej_neg(&tmpj, &groupj[i]);
+ ge_equals_gej(&group[order - i], &tmpj);
+ }
+}
+
+void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) {
+ int i, j, r_log;
+ for (r_log = 1; r_log < order; r_log++) {
+ for (j = 0; j < order; j++) {
+ for (i = 0; i < order; i++) {
+ secp256k1_gej tmp;
+ secp256k1_scalar na, ng;
+ secp256k1_scalar_set_int(&na, i);
+ secp256k1_scalar_set_int(&ng, j);
+
+ secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng);
+ ge_equals_gej(&group[(i * r_log + j) % order], &tmp);
+
+ if (i > 0) {
+ secp256k1_ecmult_const(&tmp, &group[i], &ng);
+ ge_equals_gej(&group[(i * j) % order], &tmp);
+ }
+ }
+ }
+ }
+}
+
+void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) {
+ secp256k1_fe x;
+ unsigned char x_bin[32];
+ k %= EXHAUSTIVE_TEST_ORDER;
+ x = group[k].x;
+ secp256k1_fe_normalize(&x);
+ secp256k1_fe_get_b32(x_bin, &x);
+ secp256k1_scalar_set_b32(r, x_bin, NULL);
+}
+
+void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
+ 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_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 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);
+
+ /* 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);
+
+ /* Verify by calling verify */
+ secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s);
+ memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));
+ secp256k1_pubkey_save(&pk, &nonconst_ge);
+ secp256k1_scalar_get_b32(msg32, &msg_s);
+ CHECK(should_verify ==
+ secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));
+ }
+ }
+ }
+ }
+}
+
+void test_exhaustive_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 */
+ secp256k1_ecdsa_signature sig;
+ secp256k1_scalar sk, msg, r, s, expected_r;
+ unsigned char sk32[32], msg32[32];
+ 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(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k);
+
+ 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);
+ }
+ }
+ }
+
+ /* We would like to verify zero-knowledge here by counting how often every
+ * possible (s, r) tuple appears, but because the group order is larger
+ * than the field order, when coercing the x-values to scalar values, some
+ * appear more often than others, so we are actually not zero-knowledge.
+ * (This effect also appears in the real code, but the difference is on the
+ * order of 1/2^128th the field order, so the deviation is not useful to a
+ * computationally bounded attacker.)
+ */
+}
+
+int main(void) {
+ int i;
+ secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER];
+ secp256k1_ge group[EXHAUSTIVE_TEST_ORDER];
+
+ /* Build context */
+ secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+
+ /* TODO set z = 1, then do num_tests runs with random z values */
+
+ /* Generate the entire group */
+ secp256k1_gej_set_infinity(&groupj[0]);
+ secp256k1_ge_set_gej(&group[0], &groupj[0]);
+ for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) {
+ /* Set a different random z-value for each Jacobian point */
+ secp256k1_fe z;
+ random_fe(&z);
+
+ secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g);
+ secp256k1_ge_set_gej(&group[i], &groupj[i]);
+ secp256k1_gej_rescale(&groupj[i], &z);
+
+ /* Verify against ecmult_gen */
+ {
+ secp256k1_scalar scalar_i;
+ secp256k1_gej generatedj;
+ secp256k1_ge generated;
+
+ secp256k1_scalar_set_int(&scalar_i, i);
+ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i);
+ secp256k1_ge_set_gej(&generated, &generatedj);
+
+ CHECK(group[i].infinity == 0);
+ CHECK(generated.infinity == 0);
+ CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x));
+ CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y));
+ }
+ }
+
+ /* Run the tests */
+#ifdef USE_ENDOMORPHISM
+ test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER);
+#endif
+ test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER);
+ test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER);
+ test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);
+ test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);
+
+ return 0;
+}
+
diff --git a/src/serialize.h b/src/serialize.h
index 378ed39074..e82ddf2c5a 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -13,6 +13,7 @@
#include <ios>
#include <limits>
#include <map>
+#include <memory>
#include <set>
#include <stdint.h>
#include <string>
@@ -25,6 +26,20 @@
static const unsigned int MAX_SIZE = 0x02000000;
/**
+ * Dummy data type to identify deserializing constructors.
+ *
+ * By convention, a constructor of a type T with signature
+ *
+ * template <typename Stream> T::T(deserialize_type, Stream& s)
+ *
+ * is a deserializing constructor, which builds the type by
+ * deserializing it from s. If T contains const fields, this
+ * is likely the only way to do so.
+ */
+struct deserialize_type {};
+constexpr deserialize_type deserialize {};
+
+/**
* Used to bypass the rule against non-const reference to temporary
* where it makes sense with wrappers such as CFlatData or CTxDB
*/
@@ -44,35 +59,6 @@ inline T* NCONST_PTR(const T* val)
return const_cast<T*>(val);
}
-/**
- * Get begin pointer of vector (non-const version).
- * @note These functions avoid the undefined case of indexing into an empty
- * vector, as well as that of indexing after the end of the vector.
- */
-template <typename V>
-inline typename V::value_type* begin_ptr(V& v)
-{
- return v.empty() ? NULL : &v[0];
-}
-/** Get begin pointer of vector (const version) */
-template <typename V>
-inline const typename V::value_type* begin_ptr(const V& v)
-{
- return v.empty() ? NULL : &v[0];
-}
-/** Get end pointer of vector (non-const version) */
-template <typename V>
-inline typename V::value_type* end_ptr(V& v)
-{
- return v.empty() ? NULL : (&v[0] + v.size());
-}
-/** Get end pointer of vector (const version) */
-template <typename V>
-inline const typename V::value_type* end_ptr(const V& v)
-{
- return v.empty() ? NULL : (&v[0] + v.size());
-}
-
/*
* Lowest-level serialization and conversion.
* @note Sizes of these types are verified in the tests
@@ -152,6 +138,8 @@ inline float ser_uint32_to_float(uint32_t y)
// i.e. anything that supports .read(char*, size_t) and .write(char*, size_t)
//
+class CSizeComputer;
+
enum
{
// primary actions
@@ -160,7 +148,8 @@ enum
SER_GETHASH = (1 << 2),
};
-#define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action))
+#define READWRITE(obj) (::SerReadWrite(s, (obj), ser_action))
+#define READWRITEMANY(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__))
/**
* Implement three methods for serializable objects. These are actually wrappers over
@@ -168,63 +157,42 @@ enum
* code. Adding "ADD_SERIALIZE_METHODS" in the body of the class causes these wrappers to be
* added as members.
*/
-#define ADD_SERIALIZE_METHODS \
- size_t GetSerializeSize(int nType, int nVersion) const { \
- CSizeComputer s(nType, nVersion); \
- NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\
- return s.size(); \
- } \
- template<typename Stream> \
- void Serialize(Stream& s, int nType, int nVersion) const { \
- NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\
- } \
- template<typename Stream> \
- void Unserialize(Stream& s, int nType, int nVersion) { \
- SerializationOp(s, CSerActionUnserialize(), nType, nVersion); \
+#define ADD_SERIALIZE_METHODS \
+ template<typename Stream> \
+ void Serialize(Stream& s) const { \
+ NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize()); \
+ } \
+ template<typename Stream> \
+ void Unserialize(Stream& s) { \
+ SerializationOp(s, CSerActionUnserialize()); \
}
-/*
- * Basic Types
- */
-inline unsigned int GetSerializeSize(char a, int, int=0) { return 1; }
-inline unsigned int GetSerializeSize(int8_t a, int, int=0) { return 1; }
-inline unsigned int GetSerializeSize(uint8_t a, int, int=0) { return 1; }
-inline unsigned int GetSerializeSize(int16_t a, int, int=0) { return 2; }
-inline unsigned int GetSerializeSize(uint16_t a, int, int=0) { return 2; }
-inline unsigned int GetSerializeSize(int32_t a, int, int=0) { return 4; }
-inline unsigned int GetSerializeSize(uint32_t a, int, int=0) { return 4; }
-inline unsigned int GetSerializeSize(int64_t a, int, int=0) { return 8; }
-inline unsigned int GetSerializeSize(uint64_t a, int, int=0) { return 8; }
-inline unsigned int GetSerializeSize(float a, int, int=0) { return 4; }
-inline unsigned int GetSerializeSize(double a, int, int=0) { return 8; }
-
-template<typename Stream> inline void Serialize(Stream& s, char a, int, int=0) { ser_writedata8(s, a); } // TODO Get rid of bare char
-template<typename Stream> inline void Serialize(Stream& s, int8_t a, int, int=0) { ser_writedata8(s, a); }
-template<typename Stream> inline void Serialize(Stream& s, uint8_t a, int, int=0) { ser_writedata8(s, a); }
-template<typename Stream> inline void Serialize(Stream& s, int16_t a, int, int=0) { ser_writedata16(s, a); }
-template<typename Stream> inline void Serialize(Stream& s, uint16_t a, int, int=0) { ser_writedata16(s, a); }
-template<typename Stream> inline void Serialize(Stream& s, int32_t a, int, int=0) { ser_writedata32(s, a); }
-template<typename Stream> inline void Serialize(Stream& s, uint32_t a, int, int=0) { ser_writedata32(s, a); }
-template<typename Stream> inline void Serialize(Stream& s, int64_t a, int, int=0) { ser_writedata64(s, a); }
-template<typename Stream> inline void Serialize(Stream& s, uint64_t a, int, int=0) { ser_writedata64(s, a); }
-template<typename Stream> inline void Serialize(Stream& s, float a, int, int=0) { ser_writedata32(s, ser_float_to_uint32(a)); }
-template<typename Stream> inline void Serialize(Stream& s, double a, int, int=0) { ser_writedata64(s, ser_double_to_uint64(a)); }
-
-template<typename Stream> inline void Unserialize(Stream& s, char& a, int, int=0) { a = ser_readdata8(s); } // TODO Get rid of bare char
-template<typename Stream> inline void Unserialize(Stream& s, int8_t& a, int, int=0) { a = ser_readdata8(s); }
-template<typename Stream> inline void Unserialize(Stream& s, uint8_t& a, int, int=0) { a = ser_readdata8(s); }
-template<typename Stream> inline void Unserialize(Stream& s, int16_t& a, int, int=0) { a = ser_readdata16(s); }
-template<typename Stream> inline void Unserialize(Stream& s, uint16_t& a, int, int=0) { a = ser_readdata16(s); }
-template<typename Stream> inline void Unserialize(Stream& s, int32_t& a, int, int=0) { a = ser_readdata32(s); }
-template<typename Stream> inline void Unserialize(Stream& s, uint32_t& a, int, int=0) { a = ser_readdata32(s); }
-template<typename Stream> inline void Unserialize(Stream& s, int64_t& a, int, int=0) { a = ser_readdata64(s); }
-template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a, int, int=0) { a = ser_readdata64(s); }
-template<typename Stream> inline void Unserialize(Stream& s, float& a, int, int=0) { a = ser_uint32_to_float(ser_readdata32(s)); }
-template<typename Stream> inline void Unserialize(Stream& s, double& a, int, int=0) { a = ser_uint64_to_double(ser_readdata64(s)); }
-
-inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); }
-template<typename Stream> inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; ser_writedata8(s, f); }
-template<typename Stream> inline void Unserialize(Stream& s, bool& a, int, int=0) { char f=ser_readdata8(s); a=f; }
+template<typename Stream> inline void Serialize(Stream& s, char a ) { ser_writedata8(s, a); } // TODO Get rid of bare char
+template<typename Stream> inline void Serialize(Stream& s, int8_t a ) { ser_writedata8(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, uint8_t a ) { ser_writedata8(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, int16_t a ) { ser_writedata16(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, uint16_t a) { ser_writedata16(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, int32_t a ) { ser_writedata32(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, uint32_t a) { ser_writedata32(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, int64_t a ) { ser_writedata64(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, float a ) { ser_writedata32(s, ser_float_to_uint32(a)); }
+template<typename Stream> inline void Serialize(Stream& s, double a ) { ser_writedata64(s, ser_double_to_uint64(a)); }
+
+template<typename Stream> inline void Unserialize(Stream& s, char& a ) { a = ser_readdata8(s); } // TODO Get rid of bare char
+template<typename Stream> inline void Unserialize(Stream& s, int8_t& a ) { a = ser_readdata8(s); }
+template<typename Stream> inline void Unserialize(Stream& s, uint8_t& a ) { a = ser_readdata8(s); }
+template<typename Stream> inline void Unserialize(Stream& s, int16_t& a ) { a = ser_readdata16(s); }
+template<typename Stream> inline void Unserialize(Stream& s, uint16_t& a) { a = ser_readdata16(s); }
+template<typename Stream> inline void Unserialize(Stream& s, int32_t& a ) { a = ser_readdata32(s); }
+template<typename Stream> inline void Unserialize(Stream& s, uint32_t& a) { a = ser_readdata32(s); }
+template<typename Stream> inline void Unserialize(Stream& s, int64_t& a ) { a = ser_readdata64(s); }
+template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); }
+template<typename Stream> inline void Unserialize(Stream& s, float& a ) { a = ser_uint32_to_float(ser_readdata32(s)); }
+template<typename Stream> inline void Unserialize(Stream& s, double& a ) { a = ser_uint64_to_double(ser_readdata64(s)); }
+
+template<typename Stream> inline void Serialize(Stream& s, bool a) { char f=a; ser_writedata8(s, f); }
+template<typename Stream> inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; }
@@ -246,6 +214,8 @@ inline unsigned int GetSizeOfCompactSize(uint64_t nSize)
else return sizeof(unsigned char) + sizeof(uint64_t);
}
+inline void WriteCompactSize(CSizeComputer& os, uint64_t nSize);
+
template<typename Stream>
void WriteCompactSize(Stream& os, uint64_t nSize)
{
@@ -322,8 +292,8 @@ uint64_t ReadCompactSize(Stream& is)
* 0: [0x00] 256: [0x81 0x00]
* 1: [0x01] 16383: [0xFE 0x7F]
* 127: [0x7F] 16384: [0xFF 0x00]
- * 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F]
- * 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F]
+ * 128: [0x80 0x00] 16511: [0xFF 0x7F]
+ * 255: [0x80 0x7F] 65535: [0x82 0xFE 0x7F]
* 2^32: [0x8E 0xFE 0xFE 0xFF 0x00]
*/
@@ -340,6 +310,9 @@ inline unsigned int GetSizeOfVarInt(I n)
return nRet;
}
+template<typename I>
+inline void WriteVarInt(CSizeComputer& os, I n);
+
template<typename Stream, typename I>
void WriteVarInt(Stream& os, I n)
{
@@ -363,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;
+ }
}
}
@@ -389,33 +369,28 @@ public:
template <class T, class TAl>
explicit CFlatData(std::vector<T,TAl> &v)
{
- pbegin = (char*)begin_ptr(v);
- pend = (char*)end_ptr(v);
+ pbegin = (char*)v.data();
+ pend = (char*)(v.data() + v.size());
}
template <unsigned int N, typename T, typename S, typename D>
explicit CFlatData(prevector<N, T, S, D> &v)
{
- pbegin = (char*)begin_ptr(v);
- pend = (char*)end_ptr(v);
+ pbegin = (char*)v.data();
+ pend = (char*)(v.data() + v.size());
}
char* begin() { return pbegin; }
const char* begin() const { return pbegin; }
char* end() { return pend; }
const char* end() const { return pend; }
- unsigned int GetSerializeSize(int, int=0) const
- {
- return pend - pbegin;
- }
-
template<typename Stream>
- void Serialize(Stream& s, int, int=0) const
+ void Serialize(Stream& s) const
{
s.write(pbegin, pend - pbegin);
}
template<typename Stream>
- void Unserialize(Stream& s, int, int=0)
+ void Unserialize(Stream& s)
{
s.read(pbegin, pend - pbegin);
}
@@ -429,17 +404,13 @@ protected:
public:
CVarInt(I& nIn) : n(nIn) { }
- unsigned int GetSerializeSize(int, int) const {
- return GetSizeOfVarInt<I>(n);
- }
-
template<typename Stream>
- void Serialize(Stream &s, int, int) const {
+ void Serialize(Stream &s) const {
WriteVarInt<Stream,I>(s, n);
}
template<typename Stream>
- void Unserialize(Stream& s, int, int) {
+ void Unserialize(Stream& s) {
n = ReadVarInt<Stream,I>(s);
}
};
@@ -451,17 +422,13 @@ protected:
public:
CCompactSize(uint64_t& nIn) : n(nIn) { }
- unsigned int GetSerializeSize(int, int) const {
- return GetSizeOfCompactSize(n);
- }
-
template<typename Stream>
- void Serialize(Stream &s, int, int) const {
+ void Serialize(Stream &s) const {
WriteCompactSize<Stream>(s, n);
}
template<typename Stream>
- void Unserialize(Stream& s, int, int) {
+ void Unserialize(Stream& s) {
n = ReadCompactSize<Stream>(s);
}
};
@@ -472,10 +439,10 @@ class LimitedString
protected:
std::string& string;
public:
- LimitedString(std::string& string) : string(string) {}
+ LimitedString(std::string& _string) : string(_string) {}
template<typename Stream>
- void Unserialize(Stream& s, int, int=0)
+ void Unserialize(Stream& s)
{
size_t size = ReadCompactSize(s);
if (size > Limit) {
@@ -487,17 +454,12 @@ public:
}
template<typename Stream>
- void Serialize(Stream& s, int, int=0) const
+ void Serialize(Stream& s) const
{
WriteCompactSize(s, string.size());
if (!string.empty())
s.write((char*)&string[0], string.size());
}
-
- unsigned int GetSerializeSize(int, int=0) const
- {
- return GetSizeOfCompactSize(string.size()) + string.size();
- }
};
template<typename I>
@@ -510,85 +472,76 @@ CVarInt<I> WrapVarInt(I& n) { return CVarInt<I>(n); }
/**
* string
*/
-template<typename C> unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int=0);
-template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str, int, int=0);
-template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str, int, int=0);
+template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str);
+template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str);
/**
* prevector
* prevectors of unsigned char are a special case and are intended to be serialized as a single opaque blob.
*/
-template<unsigned int N, typename T> unsigned int GetSerializeSize_impl(const prevector<N, T>& v, int nType, int nVersion, const unsigned char&);
-template<unsigned int N, typename T, typename V> unsigned int GetSerializeSize_impl(const prevector<N, T>& v, int nType, int nVersion, const V&);
-template<unsigned int N, typename T> inline unsigned int GetSerializeSize(const prevector<N, T>& v, int nType, int nVersion);
-template<typename Stream, unsigned int N, typename T> void Serialize_impl(Stream& os, const prevector<N, T>& v, int nType, int nVersion, const unsigned char&);
-template<typename Stream, unsigned int N, typename T, typename V> void Serialize_impl(Stream& os, const prevector<N, T>& v, int nType, int nVersion, const V&);
-template<typename Stream, unsigned int N, typename T> inline void Serialize(Stream& os, const prevector<N, T>& v, int nType, int nVersion);
-template<typename Stream, unsigned int N, typename T> void Unserialize_impl(Stream& is, prevector<N, T>& v, int nType, int nVersion, const unsigned char&);
-template<typename Stream, unsigned int N, typename T, typename V> void Unserialize_impl(Stream& is, prevector<N, T>& v, int nType, int nVersion, const V&);
-template<typename Stream, unsigned int N, typename T> inline void Unserialize(Stream& is, prevector<N, T>& v, int nType, int nVersion);
+template<typename Stream, unsigned int N, typename T> void Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&);
+template<typename Stream, unsigned int N, typename T, typename V> void Serialize_impl(Stream& os, const prevector<N, T>& v, const V&);
+template<typename Stream, unsigned int N, typename T> inline void Serialize(Stream& os, const prevector<N, T>& v);
+template<typename Stream, unsigned int N, typename T> void Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&);
+template<typename Stream, unsigned int N, typename T, typename V> void Unserialize_impl(Stream& is, prevector<N, T>& v, const V&);
+template<typename Stream, unsigned int N, typename T> inline void Unserialize(Stream& is, prevector<N, T>& v);
/**
* vector
* vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob.
*/
-template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&);
-template<typename T, typename A, typename V> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const V&);
-template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion);
-template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&);
-template<typename Stream, typename T, typename A, typename V> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const V&);
-template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion);
-template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const unsigned char&);
-template<typename Stream, typename T, typename A, typename V> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const V&);
-template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion);
+template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, const unsigned char&);
+template<typename Stream, typename T, typename A, typename V> void Serialize_impl(Stream& os, const std::vector<T, A>& v, const V&);
+template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v);
+template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, const unsigned char&);
+template<typename Stream, typename T, typename A, typename V> void Unserialize_impl(Stream& is, std::vector<T, A>& v, const V&);
+template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v);
/**
* pair
*/
-template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion);
-template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion);
-template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion);
+template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item);
+template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item);
/**
* map
*/
-template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion);
-template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion);
-template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion);
+template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m);
+template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m);
/**
* set
*/
-template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion);
-template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion);
-template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion);
+template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m);
+template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m);
+/**
+ * shared_ptr
+ */
+template<typename Stream, typename T> void Serialize(Stream& os, const std::shared_ptr<const T>& p);
+template<typename Stream, typename T> void Unserialize(Stream& os, std::shared_ptr<const T>& p);
+/**
+ * unique_ptr
+ */
+template<typename Stream, typename T> void Serialize(Stream& os, const std::unique_ptr<const T>& p);
+template<typename Stream, typename T> void Unserialize(Stream& os, std::unique_ptr<const T>& p);
/**
* If none of the specialized versions above matched, default to calling member function.
- * "int nType" is changed to "long nType" to keep from getting an ambiguous overload error.
- * The compiler will only cast int to long if none of the other templates matched.
- * Thanks to Boost serialization for this idea.
*/
-template<typename T>
-inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion)
-{
- return a.GetSerializeSize((int)nType, nVersion);
-}
-
template<typename Stream, typename T>
-inline void Serialize(Stream& os, const T& a, long nType, int nVersion)
+inline void Serialize(Stream& os, const T& a)
{
- a.Serialize(os, (int)nType, nVersion);
+ a.Serialize(os);
}
template<typename Stream, typename T>
-inline void Unserialize(Stream& is, T& a, long nType, int nVersion)
+inline void Unserialize(Stream& is, T& a)
{
- a.Unserialize(is, (int)nType, nVersion);
+ a.Unserialize(is);
}
@@ -598,14 +551,8 @@ inline void Unserialize(Stream& is, T& a, long nType, int nVersion)
/**
* string
*/
-template<typename C>
-unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int)
-{
- return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]);
-}
-
template<typename Stream, typename C>
-void Serialize(Stream& os, const std::basic_string<C>& str, int, int)
+void Serialize(Stream& os, const std::basic_string<C>& str)
{
WriteCompactSize(os, str.size());
if (!str.empty())
@@ -613,7 +560,7 @@ void Serialize(Stream& os, const std::basic_string<C>& str, int, int)
}
template<typename Stream, typename C>
-void Unserialize(Stream& is, std::basic_string<C>& str, int, int)
+void Unserialize(Stream& is, std::basic_string<C>& str)
{
unsigned int nSize = ReadCompactSize(is);
str.resize(nSize);
@@ -626,30 +573,8 @@ void Unserialize(Stream& is, std::basic_string<C>& str, int, int)
/**
* prevector
*/
-template<unsigned int N, typename T>
-unsigned int GetSerializeSize_impl(const prevector<N, T>& v, int nType, int nVersion, const unsigned char&)
-{
- return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T));
-}
-
-template<unsigned int N, typename T, typename V>
-unsigned int GetSerializeSize_impl(const prevector<N, T>& v, int nType, int nVersion, const V&)
-{
- unsigned int nSize = GetSizeOfCompactSize(v.size());
- for (typename prevector<N, T>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
- nSize += GetSerializeSize((*vi), nType, nVersion);
- return nSize;
-}
-
-template<unsigned int N, typename T>
-inline unsigned int GetSerializeSize(const prevector<N, T>& v, int nType, int nVersion)
-{
- return GetSerializeSize_impl(v, nType, nVersion, T());
-}
-
-
template<typename Stream, unsigned int N, typename T>
-void Serialize_impl(Stream& os, const prevector<N, T>& v, int nType, int nVersion, const unsigned char&)
+void Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&)
{
WriteCompactSize(os, v.size());
if (!v.empty())
@@ -657,22 +582,22 @@ void Serialize_impl(Stream& os, const prevector<N, T>& v, int nType, int nVersio
}
template<typename Stream, unsigned int N, typename T, typename V>
-void Serialize_impl(Stream& os, const prevector<N, T>& v, int nType, int nVersion, const V&)
+void Serialize_impl(Stream& os, const prevector<N, T>& v, const V&)
{
WriteCompactSize(os, v.size());
for (typename prevector<N, T>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
- ::Serialize(os, (*vi), nType, nVersion);
+ ::Serialize(os, (*vi));
}
template<typename Stream, unsigned int N, typename T>
-inline void Serialize(Stream& os, const prevector<N, T>& v, int nType, int nVersion)
+inline void Serialize(Stream& os, const prevector<N, T>& v)
{
- Serialize_impl(os, v, nType, nVersion, T());
+ Serialize_impl(os, v, T());
}
template<typename Stream, unsigned int N, typename T>
-void Unserialize_impl(Stream& is, prevector<N, T>& v, int nType, int nVersion, const unsigned char&)
+void Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&)
{
// Limit size per read so bogus size value won't cause out of memory
v.clear();
@@ -688,7 +613,7 @@ void Unserialize_impl(Stream& is, prevector<N, T>& v, int nType, int nVersion, c
}
template<typename Stream, unsigned int N, typename T, typename V>
-void Unserialize_impl(Stream& is, prevector<N, T>& v, int nType, int nVersion, const V&)
+void Unserialize_impl(Stream& is, prevector<N, T>& v, const V&)
{
v.clear();
unsigned int nSize = ReadCompactSize(is);
@@ -701,14 +626,14 @@ void Unserialize_impl(Stream& is, prevector<N, T>& v, int nType, int nVersion, c
nMid = nSize;
v.resize(nMid);
for (; i < nMid; i++)
- Unserialize(is, v[i], nType, nVersion);
+ Unserialize(is, v[i]);
}
}
template<typename Stream, unsigned int N, typename T>
-inline void Unserialize(Stream& is, prevector<N, T>& v, int nType, int nVersion)
+inline void Unserialize(Stream& is, prevector<N, T>& v)
{
- Unserialize_impl(is, v, nType, nVersion, T());
+ Unserialize_impl(is, v, T());
}
@@ -716,30 +641,8 @@ inline void Unserialize(Stream& is, prevector<N, T>& v, int nType, int nVersion)
/**
* vector
*/
-template<typename T, typename A>
-unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&)
-{
- return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T));
-}
-
-template<typename T, typename A, typename V>
-unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const V&)
-{
- unsigned int nSize = GetSizeOfCompactSize(v.size());
- for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
- nSize += GetSerializeSize((*vi), nType, nVersion);
- return nSize;
-}
-
-template<typename T, typename A>
-inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion)
-{
- return GetSerializeSize_impl(v, nType, nVersion, T());
-}
-
-
template<typename Stream, typename T, typename A>
-void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&)
+void Serialize_impl(Stream& os, const std::vector<T, A>& v, const unsigned char&)
{
WriteCompactSize(os, v.size());
if (!v.empty())
@@ -747,22 +650,22 @@ void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVers
}
template<typename Stream, typename T, typename A, typename V>
-void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const V&)
+void Serialize_impl(Stream& os, const std::vector<T, A>& v, const V&)
{
WriteCompactSize(os, v.size());
for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
- ::Serialize(os, (*vi), nType, nVersion);
+ ::Serialize(os, (*vi));
}
template<typename Stream, typename T, typename A>
-inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion)
+inline void Serialize(Stream& os, const std::vector<T, A>& v)
{
- Serialize_impl(os, v, nType, nVersion, T());
+ Serialize_impl(os, v, T());
}
template<typename Stream, typename T, typename A>
-void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const unsigned char&)
+void Unserialize_impl(Stream& is, std::vector<T, A>& v, const unsigned char&)
{
// Limit size per read so bogus size value won't cause out of memory
v.clear();
@@ -778,7 +681,7 @@ void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion,
}
template<typename Stream, typename T, typename A, typename V>
-void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const V&)
+void Unserialize_impl(Stream& is, std::vector<T, A>& v, const V&)
{
v.clear();
unsigned int nSize = ReadCompactSize(is);
@@ -791,14 +694,14 @@ void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion,
nMid = nSize;
v.resize(nMid);
for (; i < nMid; i++)
- Unserialize(is, v[i], nType, nVersion);
+ Unserialize(is, v[i]);
}
}
template<typename Stream, typename T, typename A>
-inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion)
+inline void Unserialize(Stream& is, std::vector<T, A>& v)
{
- Unserialize_impl(is, v, nType, nVersion, T());
+ Unserialize_impl(is, v, T());
}
@@ -806,24 +709,18 @@ inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersio
/**
* pair
*/
-template<typename K, typename T>
-unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion)
-{
- return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion);
-}
-
template<typename Stream, typename K, typename T>
-void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion)
+void Serialize(Stream& os, const std::pair<K, T>& item)
{
- Serialize(os, item.first, nType, nVersion);
- Serialize(os, item.second, nType, nVersion);
+ Serialize(os, item.first);
+ Serialize(os, item.second);
}
template<typename Stream, typename K, typename T>
-void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion)
+void Unserialize(Stream& is, std::pair<K, T>& item)
{
- Unserialize(is, item.first, nType, nVersion);
- Unserialize(is, item.second, nType, nVersion);
+ Unserialize(is, item.first);
+ Unserialize(is, item.second);
}
@@ -831,25 +728,16 @@ void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion)
/**
* map
*/
-template<typename K, typename T, typename Pred, typename A>
-unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion)
-{
- unsigned int nSize = GetSizeOfCompactSize(m.size());
- for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
- nSize += GetSerializeSize((*mi), nType, nVersion);
- return nSize;
-}
-
template<typename Stream, typename K, typename T, typename Pred, typename A>
-void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion)
+void Serialize(Stream& os, const std::map<K, T, Pred, A>& m)
{
WriteCompactSize(os, m.size());
for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
- Serialize(os, (*mi), nType, nVersion);
+ Serialize(os, (*mi));
}
template<typename Stream, typename K, typename T, typename Pred, typename A>
-void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion)
+void Unserialize(Stream& is, std::map<K, T, Pred, A>& m)
{
m.clear();
unsigned int nSize = ReadCompactSize(is);
@@ -857,7 +745,7 @@ void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion
for (unsigned int i = 0; i < nSize; i++)
{
std::pair<K, T> item;
- Unserialize(is, item, nType, nVersion);
+ Unserialize(is, item);
mi = m.insert(mi, item);
}
}
@@ -867,25 +755,16 @@ void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion
/**
* set
*/
-template<typename K, typename Pred, typename A>
-unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion)
-{
- unsigned int nSize = GetSizeOfCompactSize(m.size());
- for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it)
- nSize += GetSerializeSize((*it), nType, nVersion);
- return nSize;
-}
-
template<typename Stream, typename K, typename Pred, typename A>
-void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion)
+void Serialize(Stream& os, const std::set<K, Pred, A>& m)
{
WriteCompactSize(os, m.size());
for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it)
- Serialize(os, (*it), nType, nVersion);
+ Serialize(os, (*it));
}
template<typename Stream, typename K, typename Pred, typename A>
-void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion)
+void Unserialize(Stream& is, std::set<K, Pred, A>& m)
{
m.clear();
unsigned int nSize = ReadCompactSize(is);
@@ -893,7 +772,7 @@ void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion)
for (unsigned int i = 0; i < nSize; i++)
{
K key;
- Unserialize(is, key, nType, nVersion);
+ Unserialize(is, key);
it = m.insert(it, key);
}
}
@@ -901,27 +780,61 @@ void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion)
/**
+ * unique_ptr
+ */
+template<typename Stream, typename T> void
+Serialize(Stream& os, const std::unique_ptr<const T>& p)
+{
+ Serialize(os, *p);
+}
+
+template<typename Stream, typename T>
+void Unserialize(Stream& is, std::unique_ptr<const T>& p)
+{
+ p.reset(new T(deserialize, is));
+}
+
+
+
+/**
+ * shared_ptr
+ */
+template<typename Stream, typename T> void
+Serialize(Stream& os, const std::shared_ptr<const T>& p)
+{
+ Serialize(os, *p);
+}
+
+template<typename Stream, typename T>
+void Unserialize(Stream& is, std::shared_ptr<const T>& p)
+{
+ p = std::make_shared<const T>(deserialize, is);
+}
+
+
+
+/**
* Support for ADD_SERIALIZE_METHODS and READWRITE macro
*/
struct CSerActionSerialize
{
- bool ForRead() const { return false; }
+ constexpr bool ForRead() const { return false; }
};
struct CSerActionUnserialize
{
- bool ForRead() const { return true; }
+ constexpr bool ForRead() const { return true; }
};
template<typename Stream, typename T>
-inline void SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action)
+inline void SerReadWrite(Stream& s, const T& obj, CSerActionSerialize ser_action)
{
- ::Serialize(s, obj, nType, nVersion);
+ ::Serialize(s, obj);
}
template<typename Stream, typename T>
-inline void SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action)
+inline void SerReadWrite(Stream& s, T& obj, CSerActionUnserialize ser_action)
{
- ::Unserialize(s, obj, nType, nVersion);
+ ::Unserialize(s, obj);
}
@@ -932,33 +845,122 @@ inline void SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionU
+/* ::GetSerializeSize implementations
+ *
+ * Computing the serialized size of objects is done through a special stream
+ * object of type CSizeComputer, which only records the number of bytes written
+ * to it.
+ *
+ * If your Serialize or SerializationOp method has non-trivial overhead for
+ * serialization, it may be worthwhile to implement a specialized version for
+ * CSizeComputer, which uses the s.seek() method to record bytes that would
+ * be written instead.
+ */
class CSizeComputer
{
protected:
size_t nSize;
+ const int nType;
+ const int nVersion;
public:
- int nType;
- int nVersion;
-
CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {}
- CSizeComputer& write(const char *psz, size_t nSize)
+ void write(const char *psz, size_t _nSize)
+ {
+ this->nSize += _nSize;
+ }
+
+ /** Pretend _nSize bytes are written, without specifying them. */
+ void seek(size_t _nSize)
{
- this->nSize += nSize;
- return *this;
+ this->nSize += _nSize;
}
template<typename T>
CSizeComputer& operator<<(const T& obj)
{
- ::Serialize(*this, obj, nType, nVersion);
+ ::Serialize(*this, obj);
return (*this);
}
size_t size() const {
return nSize;
}
+
+ int GetVersion() const { return nVersion; }
+ int GetType() const { return nType; }
};
+template<typename Stream>
+void SerializeMany(Stream& s)
+{
+}
+
+template<typename Stream, typename Arg>
+void SerializeMany(Stream& s, Arg&& arg)
+{
+ ::Serialize(s, std::forward<Arg>(arg));
+}
+
+template<typename Stream, typename Arg, typename... Args>
+void SerializeMany(Stream& s, Arg&& arg, Args&&... args)
+{
+ ::Serialize(s, std::forward<Arg>(arg));
+ ::SerializeMany(s, std::forward<Args>(args)...);
+}
+
+template<typename Stream>
+inline void UnserializeMany(Stream& s)
+{
+}
+
+template<typename Stream, typename Arg>
+inline void UnserializeMany(Stream& s, Arg& arg)
+{
+ ::Unserialize(s, arg);
+}
+
+template<typename Stream, typename Arg, typename... Args>
+inline void UnserializeMany(Stream& s, Arg& arg, Args&... args)
+{
+ ::Unserialize(s, arg);
+ ::UnserializeMany(s, args...);
+}
+
+template<typename Stream, typename... Args>
+inline void SerReadWriteMany(Stream& s, CSerActionSerialize ser_action, Args&&... args)
+{
+ ::SerializeMany(s, std::forward<Args>(args)...);
+}
+
+template<typename Stream, typename... Args>
+inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&... args)
+{
+ ::UnserializeMany(s, args...);
+}
+
+template<typename I>
+inline void WriteVarInt(CSizeComputer &s, I n)
+{
+ s.seek(GetSizeOfVarInt<I>(n));
+}
+
+inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize)
+{
+ s.seek(GetSizeOfCompactSize(nSize));
+}
+
+template <typename T>
+size_t GetSerializeSize(const T& t, int nType, int nVersion = 0)
+{
+ return (CSizeComputer(nType, nVersion) << t).size();
+}
+
+template <typename S, typename T>
+size_t GetSerializeSize(const S& s, const T& t)
+{
+ return (CSizeComputer(s.GetType(), s.GetVersion()) << t).size();
+}
+
#endif // BITCOIN_SERIALIZE_H
diff --git a/src/streams.h b/src/streams.h
index 7132364eb1..8dc5a19ead 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -26,17 +26,18 @@ template<typename Stream>
class OverrideStream
{
Stream* stream;
-public:
+
const int nType;
const int nVersion;
+public:
OverrideStream(Stream* stream_, int nType_, int nVersion_) : stream(stream_), nType(nType_), nVersion(nVersion_) {}
template<typename T>
OverrideStream<Stream>& operator<<(const T& obj)
{
// Serialize to this stream
- ::Serialize(*this->stream, obj, nType, nVersion);
+ ::Serialize(*this, obj);
return (*this);
}
@@ -44,9 +45,22 @@ public:
OverrideStream<Stream>& operator>>(T& obj)
{
// Unserialize from this stream
- ::Unserialize(*this->stream, obj, nType, nVersion);
+ ::Unserialize(*this, obj);
return (*this);
}
+
+ void write(const char* pch, size_t nSize)
+ {
+ stream->write(pch, nSize);
+ }
+
+ void read(char* pch, size_t nSize)
+ {
+ stream->read(pch, nSize);
+ }
+
+ int GetVersion() const { return nVersion; }
+ int GetType() const { return nType; }
};
template<typename S>
@@ -55,6 +69,75 @@ OverrideStream<S> WithOrVersion(S* s, int nVersionFlag)
return OverrideStream<S>(s, s->GetType(), s->GetVersion() | nVersionFlag);
}
+/* Minimal stream for overwriting and/or appending to an existing byte vector
+ *
+ * The referenced vector will grow as necessary
+ */
+class CVectorWriter
+{
+ public:
+
+/*
+ * @param[in] nTypeIn Serialization Type
+ * @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().
+*/
+ CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
+ {
+ if(nPos > vchData.size())
+ vchData.resize(nPos);
+ }
+/*
+ * (other params same as above)
+ * @param[in] args A list of items to serialize starting at nPos.
+*/
+ template <typename... Args>
+ CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
+ {
+ ::SerializeMany(*this, std::forward<Args>(args)...);
+ }
+ void write(const char* pch, size_t nSize)
+ {
+ assert(nPos <= vchData.size());
+ size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
+ if (nOverwrite) {
+ memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite);
+ }
+ if (nOverwrite < nSize) {
+ vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize);
+ }
+ nPos += nSize;
+ }
+ template<typename T>
+ CVectorWriter& operator<<(const T& obj)
+ {
+ // Serialize to this stream
+ ::Serialize(*this, obj);
+ return (*this);
+ }
+ int GetVersion() const
+ {
+ return nVersion;
+ }
+ int GetType() const
+ {
+ return nType;
+ }
+ void seek(size_t nSize)
+ {
+ nPos += nSize;
+ if(nPos > vchData.size())
+ vchData.resize(nPos);
+ }
+private:
+ const int nType;
+ const int nVersion;
+ std::vector<unsigned char>& vchData;
+ size_t nPos;
+};
+
/** Double ended buffer combining vector and stream-like interfaces.
*
* >> and << read and write unformatted data using the above serialization templates.
@@ -66,9 +149,10 @@ protected:
typedef CSerializeData vector_type;
vector_type vch;
unsigned int nReadPos;
-public:
+
int nType;
int nVersion;
+public:
typedef vector_type::allocator_type allocator_type;
typedef vector_type::size_type size_type;
@@ -90,12 +174,10 @@ public:
Init(nTypeIn, nVersionIn);
}
-#if !defined(_MSC_VER) || _MSC_VER >= 1300
CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
{
Init(nTypeIn, nVersionIn);
}
-#endif
CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
{
@@ -112,6 +194,13 @@ public:
Init(nTypeIn, nVersionIn);
}
+ template <typename... Args>
+ CDataStream(int nTypeIn, int nVersionIn, Args&&... args)
+ {
+ Init(nTypeIn, nVersionIn);
+ ::SerializeMany(*this, std::forward<Args>(args)...);
+ }
+
void Init(int nTypeIn, int nVersionIn)
{
nReadPos = 0;
@@ -154,10 +243,13 @@ public:
void clear() { vch.clear(); nReadPos = 0; }
iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); }
void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); }
+ value_type* data() { return vch.data() + nReadPos; }
+ const value_type* data() const { return vch.data() + nReadPos; }
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
@@ -168,10 +260,10 @@ public:
vch.insert(it, first, last);
}
-#if !defined(_MSC_VER) || _MSC_VER >= 1300
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
@@ -181,7 +273,6 @@ public:
else
vch.insert(it, first, last);
}
-#endif
iterator erase(iterator it)
{
@@ -244,14 +335,14 @@ public:
int in_avail() { return size(); }
void SetType(int n) { nType = n; }
- int GetType() { return nType; }
+ int GetType() const { return nType; }
void SetVersion(int n) { nVersion = n; }
- int GetVersion() { return nVersion; }
- void ReadVersion() { *this >> nVersion; }
- void WriteVersion() { *this << nVersion; }
+ int GetVersion() const { return nVersion; }
- CDataStream& read(char* pch, size_t nSize)
+ 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())
@@ -263,14 +354,13 @@ public:
memcpy(pch, &vch[nReadPos], nSize);
nReadPos = 0;
vch.clear();
- return (*this);
+ return;
}
memcpy(pch, &vch[nReadPos], nSize);
nReadPos = nReadPosNext;
- return (*this);
}
- CDataStream& ignore(int nSize)
+ void ignore(int nSize)
{
// Ignore from the beginning of the buffer
if (nSize < 0) {
@@ -283,21 +373,19 @@ public:
throw std::ios_base::failure("CDataStream::ignore(): end of data");
nReadPos = 0;
vch.clear();
- return (*this);
+ return;
}
nReadPos = nReadPosNext;
- return (*this);
}
- CDataStream& write(const char* pch, size_t nSize)
+ void write(const char* pch, size_t nSize)
{
// Write to the end of the buffer
vch.insert(vch.end(), pch, pch + nSize);
- return (*this);
}
template<typename Stream>
- void Serialize(Stream& s, int nType, int nVersion) const
+ void Serialize(Stream& s) const
{
// Special case: stream << stream concatenates like stream += stream
if (!vch.empty())
@@ -305,17 +393,10 @@ public:
}
template<typename T>
- unsigned int GetSerializeSize(const T& obj)
- {
- // Tells the size of the object if serialized to this stream
- return ::GetSerializeSize(obj, nType, nVersion);
- }
-
- template<typename T>
CDataStream& operator<<(const T& obj)
{
// Serialize to this stream
- ::Serialize(*this, obj, nType, nVersion);
+ ::Serialize(*this, obj);
return (*this);
}
@@ -323,12 +404,12 @@ public:
CDataStream& operator>>(T& obj)
{
// Unserialize from this stream
- ::Unserialize(*this, obj, nType, nVersion);
+ ::Unserialize(*this, obj);
return (*this);
}
- void GetAndClear(CSerializeData &data) {
- data.insert(data.end(), begin(), end());
+ void GetAndClear(CSerializeData &d) {
+ d.insert(d.end(), begin(), end());
clear();
}
@@ -378,17 +459,15 @@ private:
CAutoFile(const CAutoFile&);
CAutoFile& operator=(const CAutoFile&);
- int nType;
- int nVersion;
-
+ const int nType;
+ const int nVersion;
+
FILE* file;
public:
- CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn)
+ CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
{
file = filenew;
- nType = nTypeIn;
- nVersion = nVersionIn;
}
~CAutoFile()
@@ -423,23 +502,18 @@ public:
//
// Stream subset
//
- void SetType(int n) { nType = n; }
- int GetType() { return nType; }
- void SetVersion(int n) { nVersion = n; }
- int GetVersion() { return nVersion; }
- void ReadVersion() { *this >> nVersion; }
- void WriteVersion() { *this << nVersion; }
+ int GetType() const { return nType; }
+ int GetVersion() const { return nVersion; }
- CAutoFile& read(char* pch, size_t nSize)
+ void read(char* pch, size_t nSize)
{
if (!file)
throw std::ios_base::failure("CAutoFile::read: file handle is NULL");
if (fread(pch, 1, nSize, file) != nSize)
throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
- return (*this);
}
- CAutoFile& ignore(size_t nSize)
+ void ignore(size_t nSize)
{
if (!file)
throw std::ios_base::failure("CAutoFile::ignore: file handle is NULL");
@@ -450,23 +524,14 @@ public:
throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
nSize -= nNow;
}
- return (*this);
}
- CAutoFile& write(const char* pch, size_t nSize)
+ void write(const char* pch, size_t nSize)
{
if (!file)
throw std::ios_base::failure("CAutoFile::write: file handle is NULL");
if (fwrite(pch, 1, nSize, file) != nSize)
throw std::ios_base::failure("CAutoFile::write: write failed");
- return (*this);
- }
-
- template<typename T>
- unsigned int GetSerializeSize(const T& obj)
- {
- // Tells the size of the object if serialized to this stream
- return ::GetSerializeSize(obj, nType, nVersion);
}
template<typename T>
@@ -475,7 +540,7 @@ public:
// Serialize to this stream
if (!file)
throw std::ios_base::failure("CAutoFile::operator<<: file handle is NULL");
- ::Serialize(*this, obj, nType, nVersion);
+ ::Serialize(*this, obj);
return (*this);
}
@@ -485,7 +550,7 @@ public:
// Unserialize from this stream
if (!file)
throw std::ios_base::failure("CAutoFile::operator>>: file handle is NULL");
- ::Unserialize(*this, obj, nType, nVersion);
+ ::Unserialize(*this, obj);
return (*this);
}
};
@@ -503,8 +568,8 @@ private:
CBufferedFile(const CBufferedFile&);
CBufferedFile& operator=(const CBufferedFile&);
- int nType;
- int nVersion;
+ const int nType;
+ const int nVersion;
FILE *src; // source file
uint64_t nSrcPos; // how many bytes have been read from source
@@ -523,22 +588,20 @@ 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;
}
}
public:
CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
- nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0)
+ nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0)
{
src = fileIn;
- nType = nTypeIn;
- nVersion = nVersionIn;
}
~CBufferedFile()
@@ -546,6 +609,9 @@ public:
fclose();
}
+ int GetVersion() const { return nVersion; }
+ int GetType() const { return nType; }
+
void fclose()
{
if (src) {
@@ -560,7 +626,7 @@ public:
}
// read a number of bytes
- CBufferedFile& read(char *pch, size_t nSize) {
+ void read(char *pch, size_t nSize) {
if (nSize + nReadPos > nReadLimit)
throw std::ios_base::failure("Read attempted past buffer limit");
if (nSize + nRewind > vchBuf.size())
@@ -579,7 +645,6 @@ public:
pch += nNow;
nSize -= nNow;
}
- return (*this);
}
// return the current reading position
@@ -625,7 +690,7 @@ public:
template<typename T>
CBufferedFile& operator>>(T& obj) {
// Unserialize from this stream
- ::Unserialize(*this, obj, nType, nVersion);
+ ::Unserialize(*this, obj);
return (*this);
}
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index 1ec40fe830..9daba86ef3 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -1,12 +1,13 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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_SUPPORT_ALLOCATORS_SECURE_H
#define BITCOIN_SUPPORT_ALLOCATORS_SECURE_H
-#include "support/pagelocker.h"
+#include "support/lockedpool.h"
+#include "support/cleanse.h"
#include <string>
@@ -39,20 +40,15 @@ struct secure_allocator : public std::allocator<T> {
T* allocate(std::size_t n, const void* hint = 0)
{
- T* p;
- p = std::allocator<T>::allocate(n, hint);
- if (p != NULL)
- LockedPageManager::Instance().LockRange(p, sizeof(T) * n);
- return p;
+ return static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n));
}
void deallocate(T* p, std::size_t n)
{
if (p != NULL) {
memory_cleanse(p, sizeof(T) * n);
- LockedPageManager::Instance().UnlockRange(p, sizeof(T) * n);
}
- std::allocator<T>::deallocate(p, n);
+ LockedPoolManager::Instance().free(p);
}
};
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
new file mode 100644
index 0000000000..4f2f3cf9ef
--- /dev/null
+++ b/src/support/events.h
@@ -0,0 +1,56 @@
+// Copyright (c) 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_SUPPORT_EVENTS_H
+#define BITCOIN_SUPPORT_EVENTS_H
+
+#include <ios>
+#include <memory>
+
+#include <event2/event.h>
+#include <event2/http.h>
+
+#define MAKE_RAII(type) \
+/* deleter */\
+struct type##_deleter {\
+ void operator()(struct type* ob) {\
+ type##_free(ob);\
+ }\
+};\
+/* unique ptr typedef */\
+typedef std::unique_ptr<struct type, type##_deleter> raii_##type
+
+MAKE_RAII(event_base);
+MAKE_RAII(event);
+MAKE_RAII(evhttp);
+MAKE_RAII(evhttp_request);
+MAKE_RAII(evhttp_connection);
+
+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) {
+ return raii_event(event_new(base, s, events, cb, arg));
+}
+
+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) {
+ 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));
+ if (!result.get())
+ throw std::runtime_error("create connection failed");
+ return result;
+}
+
+#endif // BITCOIN_SUPPORT_EVENTS_H
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
new file mode 100644
index 0000000000..98c1581093
--- /dev/null
+++ b/src/support/lockedpool.cpp
@@ -0,0 +1,385 @@
+// Copyright (c) 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 "support/lockedpool.h"
+#include "support/cleanse.h"
+
+#if defined(HAVE_CONFIG_H)
+#include "config/bitcoin-config.h"
+#endif
+
+#ifdef WIN32
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0501
+#define WIN32_LEAN_AND_MEAN 1
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+#else
+#include <sys/mman.h> // for mmap
+#include <sys/resource.h> // for getrlimit
+#include <limits.h> // for PAGESIZE
+#include <unistd.h> // for sysconf
+#endif
+
+#include <algorithm>
+
+LockedPoolManager* LockedPoolManager::_instance = NULL;
+std::once_flag LockedPoolManager::init_flag;
+
+/*******************************************************************************/
+// Utilities
+//
+/** Align up to power of 2 */
+static inline size_t align_up(size_t x, size_t align)
+{
+ return (x + align - 1) & ~(align - 1);
+}
+
+/*******************************************************************************/
+// Implementation: Arena
+
+Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
+ base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)
+{
+ // Start with one free chunk that covers the entire arena
+ chunks_free.emplace(base, size_in);
+}
+
+Arena::~Arena()
+{
+}
+
+void* Arena::alloc(size_t size)
+{
+ // Round to next multiple of alignment
+ size = align_up(size, alignment);
+
+ // Don't handle zero-sized chunks
+ if (size == 0)
+ return nullptr;
+
+ // Pick a large enough free-chunk
+ auto it = std::find_if(chunks_free.begin(), chunks_free.end(),
+ [=](const std::map<char*, size_t>::value_type& chunk){ return chunk.second >= size; });
+ if (it == chunks_free.end())
+ return nullptr;
+
+ // Create the used-chunk, taking its space from the end of the free-chunk
+ auto alloced = chunks_used.emplace(it->first + it->second - size, size).first;
+ if (!(it->second -= size))
+ chunks_free.erase(it);
+ return reinterpret_cast<void*>(alloced->first);
+}
+
+/* extend the Iterator if other begins at its end */
+template <class Iterator, class Pair> bool extend(Iterator it, const Pair& other) {
+ if (it->first + it->second == other.first) {
+ it->second += other.second;
+ return true;
+ }
+ return false;
+}
+
+void Arena::free(void *ptr)
+{
+ // Freeing the NULL pointer is OK.
+ if (ptr == nullptr) {
+ return;
+ }
+
+ // Remove chunk from used map
+ auto i = chunks_used.find(static_cast<char*>(ptr));
+ if (i == chunks_used.end()) {
+ throw std::runtime_error("Arena: invalid or double free");
+ }
+ auto freed = *i;
+ chunks_used.erase(i);
+
+ // Add space to free map, coalescing contiguous chunks
+ auto next = chunks_free.upper_bound(freed.first);
+ auto prev = (next == chunks_free.begin()) ? chunks_free.end() : std::prev(next);
+ if (prev == chunks_free.end() || !extend(prev, freed))
+ prev = chunks_free.emplace_hint(next, freed);
+ if (next != chunks_free.end() && extend(prev, *next))
+ chunks_free.erase(next);
+}
+
+Arena::Stats Arena::stats() const
+{
+ Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };
+ for (const auto& chunk: chunks_used)
+ r.used += chunk.second;
+ for (const auto& chunk: chunks_free)
+ r.free += chunk.second;
+ r.total = r.used + r.free;
+ return r;
+}
+
+#ifdef ARENA_DEBUG
+void printchunk(char* base, size_t sz, bool used) {
+ std::cout <<
+ "0x" << std::hex << std::setw(16) << std::setfill('0') << base <<
+ " 0x" << std::hex << std::setw(16) << std::setfill('0') << sz <<
+ " 0x" << used << std::endl;
+}
+void Arena::walk() const
+{
+ for (const auto& chunk: chunks_used)
+ printchunk(chunk.first, chunk.second, true);
+ std::cout << std::endl;
+ for (const auto& chunk: chunks_free)
+ printchunk(chunk.first, chunk.second, false);
+ std::cout << std::endl;
+}
+#endif
+
+/*******************************************************************************/
+// Implementation: Win32LockedPageAllocator
+
+#ifdef WIN32
+/** LockedPageAllocator specialized for Windows.
+ */
+class Win32LockedPageAllocator: public LockedPageAllocator
+{
+public:
+ Win32LockedPageAllocator();
+ void* AllocateLocked(size_t len, bool *lockingSuccess);
+ void FreeLocked(void* addr, size_t len);
+ size_t GetLimit();
+private:
+ size_t page_size;
+};
+
+Win32LockedPageAllocator::Win32LockedPageAllocator()
+{
+ // Determine system page size in bytes
+ SYSTEM_INFO sSysInfo;
+ GetSystemInfo(&sSysInfo);
+ page_size = sSysInfo.dwPageSize;
+}
+void *Win32LockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
+{
+ len = align_up(len, page_size);
+ void *addr = VirtualAlloc(nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ if (addr) {
+ // VirtualLock is used to attempt to keep keying material out of swap. Note
+ // that it does not provide this as a guarantee, but, in practice, memory
+ // that has been VirtualLock'd almost never gets written to the pagefile
+ // except in rare circumstances where memory is extremely low.
+ *lockingSuccess = VirtualLock(const_cast<void*>(addr), len) != 0;
+ }
+ return addr;
+}
+void Win32LockedPageAllocator::FreeLocked(void* addr, size_t len)
+{
+ len = align_up(len, page_size);
+ memory_cleanse(addr, len);
+ VirtualUnlock(const_cast<void*>(addr), len);
+}
+
+size_t Win32LockedPageAllocator::GetLimit()
+{
+ // TODO is there a limit on windows, how to get it?
+ return std::numeric_limits<size_t>::max();
+}
+#endif
+
+/*******************************************************************************/
+// Implementation: PosixLockedPageAllocator
+
+#ifndef WIN32
+/** LockedPageAllocator specialized for OSes that don't try to be
+ * special snowflakes.
+ */
+class PosixLockedPageAllocator: public LockedPageAllocator
+{
+public:
+ PosixLockedPageAllocator();
+ void* AllocateLocked(size_t len, bool *lockingSuccess);
+ void FreeLocked(void* addr, size_t len);
+ size_t GetLimit();
+private:
+ size_t page_size;
+};
+
+PosixLockedPageAllocator::PosixLockedPageAllocator()
+{
+ // Determine system page size in bytes
+#if defined(PAGESIZE) // defined in limits.h
+ page_size = PAGESIZE;
+#else // assume some POSIX OS
+ page_size = sysconf(_SC_PAGESIZE);
+#endif
+}
+
+// Some systems (at least OS X) do not define MAP_ANONYMOUS yet and define
+// MAP_ANON which is deprecated
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+void *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)
+{
+ void *addr;
+ len = align_up(len, page_size);
+ addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ if (addr) {
+ *lockingSuccess = mlock(addr, len) == 0;
+ }
+ return addr;
+}
+void PosixLockedPageAllocator::FreeLocked(void* addr, size_t len)
+{
+ len = align_up(len, page_size);
+ memory_cleanse(addr, len);
+ munlock(addr, len);
+ munmap(addr, len);
+}
+size_t PosixLockedPageAllocator::GetLimit()
+{
+#ifdef RLIMIT_MEMLOCK
+ struct rlimit rlim;
+ if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {
+ if (rlim.rlim_cur != RLIM_INFINITY) {
+ return rlim.rlim_cur;
+ }
+ }
+#endif
+ return std::numeric_limits<size_t>::max();
+}
+#endif
+
+/*******************************************************************************/
+// Implementation: LockedPool
+
+LockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in):
+ allocator(std::move(allocator_in)), lf_cb(lf_cb_in), cumulative_bytes_locked(0)
+{
+}
+
+LockedPool::~LockedPool()
+{
+}
+void* LockedPool::alloc(size_t size)
+{
+ std::lock_guard<std::mutex> lock(mutex);
+
+ // Don't handle impossible sizes
+ if (size == 0 || size > ARENA_SIZE)
+ return nullptr;
+
+ // Try allocating from each current arena
+ for (auto &arena: arenas) {
+ void *addr = arena.alloc(size);
+ if (addr) {
+ return addr;
+ }
+ }
+ // If that fails, create a new one
+ if (new_arena(ARENA_SIZE, ARENA_ALIGN)) {
+ return arenas.back().alloc(size);
+ }
+ return nullptr;
+}
+
+void LockedPool::free(void *ptr)
+{
+ std::lock_guard<std::mutex> lock(mutex);
+ // TODO we can do better than this linear search by keeping a map of arena
+ // extents to arena, and looking up the address.
+ for (auto &arena: arenas) {
+ if (arena.addressInArena(ptr)) {
+ arena.free(ptr);
+ return;
+ }
+ }
+ throw std::runtime_error("LockedPool: invalid address not pointing to any arena");
+}
+
+LockedPool::Stats LockedPool::stats() const
+{
+ std::lock_guard<std::mutex> lock(mutex);
+ LockedPool::Stats r{0, 0, 0, cumulative_bytes_locked, 0, 0};
+ for (const auto &arena: arenas) {
+ Arena::Stats i = arena.stats();
+ r.used += i.used;
+ r.free += i.free;
+ r.total += i.total;
+ r.chunks_used += i.chunks_used;
+ r.chunks_free += i.chunks_free;
+ }
+ return r;
+}
+
+bool LockedPool::new_arena(size_t size, size_t align)
+{
+ bool locked;
+ // If this is the first arena, handle this specially: Cap the upper size
+ // by the process limit. This makes sure that the first arena will at least
+ // be locked. An exception to this is if the process limit is 0:
+ // in this case no memory can be locked at all so we'll skip past this logic.
+ if (arenas.empty()) {
+ size_t limit = allocator->GetLimit();
+ if (limit > 0) {
+ size = std::min(size, limit);
+ }
+ }
+ void *addr = allocator->AllocateLocked(size, &locked);
+ if (!addr) {
+ return false;
+ }
+ if (locked) {
+ cumulative_bytes_locked += size;
+ } else if (lf_cb) { // Call the locking-failed callback if locking failed
+ if (!lf_cb()) { // If the callback returns false, free the memory and fail, otherwise consider the user warned and proceed.
+ allocator->FreeLocked(addr, size);
+ return false;
+ }
+ }
+ arenas.emplace_back(allocator.get(), addr, size, align);
+ return true;
+}
+
+LockedPool::LockedPageArena::LockedPageArena(LockedPageAllocator *allocator_in, void *base_in, size_t size_in, size_t align_in):
+ Arena(base_in, size_in, align_in), base(base_in), size(size_in), allocator(allocator_in)
+{
+}
+LockedPool::LockedPageArena::~LockedPageArena()
+{
+ allocator->FreeLocked(base, size);
+}
+
+/*******************************************************************************/
+// Implementation: LockedPoolManager
+//
+LockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator_in):
+ LockedPool(std::move(allocator_in), &LockedPoolManager::LockingFailed)
+{
+}
+
+bool LockedPoolManager::LockingFailed()
+{
+ // TODO: log something but how? without including util.h
+ return true;
+}
+
+void LockedPoolManager::CreateInstance()
+{
+ // Using a local static instance guarantees that the object is initialized
+ // when it's first needed and also deinitialized after all objects that use
+ // it are done with it. I can think of one unlikely scenario where we may
+ // have a static deinitialization order/problem, but the check in
+ // LockedPoolManagerBase's destructor helps us detect if that ever happens.
+#ifdef WIN32
+ std::unique_ptr<LockedPageAllocator> allocator(new Win32LockedPageAllocator());
+#else
+ std::unique_ptr<LockedPageAllocator> allocator(new PosixLockedPageAllocator());
+#endif
+ static LockedPoolManager instance(std::move(allocator));
+ LockedPoolManager::_instance = &instance;
+}
diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h
new file mode 100644
index 0000000000..f5212bc266
--- /dev/null
+++ b/src/support/lockedpool.h
@@ -0,0 +1,231 @@
+// Copyright (c) 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_SUPPORT_LOCKEDPOOL_H
+#define BITCOIN_SUPPORT_LOCKEDPOOL_H
+
+#include <stdint.h>
+#include <list>
+#include <map>
+#include <mutex>
+#include <memory>
+
+/**
+ * OS-dependent allocation and deallocation of locked/pinned memory pages.
+ * Abstract base class.
+ */
+class LockedPageAllocator
+{
+public:
+ virtual ~LockedPageAllocator() {}
+ /** Allocate and lock memory pages.
+ * If len is not a multiple of the system page size, it is rounded up.
+ * Returns 0 in case of allocation failure.
+ *
+ * If locking the memory pages could not be accomplished it will still
+ * return the memory, however the lockingSuccess flag will be false.
+ * lockingSuccess is undefined if the allocation fails.
+ */
+ virtual void* AllocateLocked(size_t len, bool *lockingSuccess) = 0;
+
+ /** Unlock and free memory pages.
+ * Clear the memory before unlocking.
+ */
+ virtual void FreeLocked(void* addr, size_t len) = 0;
+
+ /** Get the total limit on the amount of memory that may be locked by this
+ * process, in bytes. Return size_t max if there is no limit or the limit
+ * is unknown. Return 0 if no memory can be locked at all.
+ */
+ virtual size_t GetLimit() = 0;
+};
+
+/* An arena manages a contiguous region of memory by dividing it into
+ * chunks.
+ */
+class Arena
+{
+public:
+ Arena(void *base, size_t size, size_t alignment);
+ virtual ~Arena();
+
+ /** Memory statistics. */
+ struct Stats
+ {
+ size_t used;
+ size_t free;
+ size_t total;
+ size_t chunks_used;
+ size_t chunks_free;
+ };
+
+ /** Allocate size bytes from this arena.
+ * Returns pointer on success, or 0 if memory is full or
+ * the application tried to allocate 0 bytes.
+ */
+ void* alloc(size_t size);
+
+ /** Free a previously allocated chunk of memory.
+ * Freeing the zero pointer has no effect.
+ * Raises std::runtime_error in case of error.
+ */
+ void free(void *ptr);
+
+ /** Get arena usage statistics */
+ Stats stats() const;
+
+#ifdef ARENA_DEBUG
+ void walk() const;
+#endif
+
+ /** Return whether a pointer points inside this arena.
+ * This returns base <= ptr < (base+size) so only use it for (inclusive)
+ * chunk starting addresses.
+ */
+ 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.
+ */
+ std::map<char*, size_t> chunks_free;
+ std::map<char*, size_t> chunks_used;
+ /** Base address of arena */
+ char* base;
+ /** End address of arena */
+ char* end;
+ /** Minimum chunk alignment */
+ size_t alignment;
+};
+
+/** Pool for locked memory chunks.
+ *
+ * To avoid sensitive key data from being swapped to disk, the memory in this pool
+ * is locked/pinned.
+ *
+ * An arena manages a contiguous region of memory. The pool starts out with one arena
+ * but can grow to multiple arenas if the need arises.
+ *
+ * Unlike a normal C heap, the administrative structures are separate from the managed
+ * memory. This has been done as the sizes and bases of objects are not in themselves sensitive
+ * information, as to conserve precious locked memory. In some operating systems
+ * the amount of memory that can be locked is small.
+ */
+class LockedPool
+{
+public:
+ /** Size of one arena of locked memory. This is a compromise.
+ * Do not set this too low, as managing many arenas will increase
+ * allocation and deallocation overhead. Setting it too high allocates
+ * more locked memory from the OS than strictly necessary.
+ */
+ static const size_t ARENA_SIZE = 256*1024;
+ /** Chunk alignment. Another compromise. Setting this too high will waste
+ * memory, setting it too low will facilitate fragmentation.
+ */
+ static const size_t ARENA_ALIGN = 16;
+
+ /** Callback when allocation succeeds but locking fails.
+ */
+ typedef bool (*LockingFailed_Callback)();
+
+ /** Memory statistics. */
+ struct Stats
+ {
+ size_t used;
+ size_t free;
+ size_t total;
+ size_t locked;
+ size_t chunks_used;
+ size_t chunks_free;
+ };
+
+ /** Create a new LockedPool. This takes ownership of the MemoryPageLocker,
+ * you can only instantiate this with LockedPool(std::move(...)).
+ *
+ * The second argument is an optional callback when locking a newly allocated arena failed.
+ * 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);
+ ~LockedPool();
+
+ /** Allocate size bytes from this arena.
+ * Returns pointer on success, or 0 if memory is full or
+ * the application tried to allocate 0 bytes.
+ */
+ void* alloc(size_t size);
+
+ /** Free a previously allocated chunk of memory.
+ * Freeing the zero pointer has no effect.
+ * Raises std::runtime_error in case of error.
+ */
+ void free(void *ptr);
+
+ /** 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 */
+ class LockedPageArena: public Arena
+ {
+ public:
+ LockedPageArena(LockedPageAllocator *alloc_in, void *base_in, size_t size, size_t align);
+ ~LockedPageArena();
+ private:
+ void *base;
+ size_t size;
+ LockedPageAllocator *allocator;
+ };
+
+ bool new_arena(size_t size, size_t align);
+
+ std::list<LockedPageArena> arenas;
+ LockingFailed_Callback lf_cb;
+ size_t cumulative_bytes_locked;
+ /** Mutex protects access to this pool's data structures, including arenas.
+ */
+ mutable std::mutex mutex;
+};
+
+/**
+ * Singleton class to keep track of locked (ie, non-swappable) memory, for use in
+ * std::allocator templates.
+ *
+ * Some implementations of the STL allocate memory in some constructors (i.e., see
+ * MSVC's vector<T> implementation where it allocates 1 byte of memory in the allocator.)
+ * Due to the unpredictable order of static initializers, we have to make sure the
+ * LockedPoolManager instance exists before any other STL-based objects that use
+ * secure_allocator are created. So instead of having LockedPoolManager also be
+ * static-initialized, it is created on demand.
+ */
+class LockedPoolManager : public LockedPool
+{
+public:
+ /** Return the current instance, or create it once */
+ static LockedPoolManager& Instance()
+ {
+ std::call_once(LockedPoolManager::init_flag, LockedPoolManager::CreateInstance);
+ return *LockedPoolManager::_instance;
+ }
+
+private:
+ LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator);
+
+ /** Create a new LockedPoolManager specialized to the OS */
+ static void CreateInstance();
+ /** Called when locking fails, warn the user here */
+ static bool LockingFailed();
+
+ static LockedPoolManager* _instance;
+ static std::once_flag init_flag;
+};
+
+#endif // BITCOIN_SUPPORT_LOCKEDPOOL_H
diff --git a/src/support/pagelocker.cpp b/src/support/pagelocker.cpp
deleted file mode 100644
index 7cea2d88c5..0000000000
--- a/src/support/pagelocker.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.
-
-#include "support/pagelocker.h"
-
-#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
-#endif
-
-#ifdef WIN32
-#ifdef _WIN32_WINNT
-#undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0501
-#define WIN32_LEAN_AND_MEAN 1
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-#include <windows.h>
-// This is used to attempt to keep keying material out of swap
-// Note that VirtualLock does not provide this as a guarantee on Windows,
-// but, in practice, memory that has been VirtualLock'd almost never gets written to
-// the pagefile except in rare circumstances where memory is extremely low.
-#else
-#include <sys/mman.h>
-#include <limits.h> // for PAGESIZE
-#include <unistd.h> // for sysconf
-#endif
-
-LockedPageManager* LockedPageManager::_instance = NULL;
-boost::once_flag LockedPageManager::init_flag = BOOST_ONCE_INIT;
-
-/** Determine system page size in bytes */
-static inline size_t GetSystemPageSize()
-{
- size_t page_size;
-#if defined(WIN32)
- SYSTEM_INFO sSysInfo;
- GetSystemInfo(&sSysInfo);
- page_size = sSysInfo.dwPageSize;
-#elif defined(PAGESIZE) // defined in limits.h
- page_size = PAGESIZE;
-#else // assume some POSIX OS
- page_size = sysconf(_SC_PAGESIZE);
-#endif
- return page_size;
-}
-
-bool MemoryPageLocker::Lock(const void* addr, size_t len)
-{
-#ifdef WIN32
- return VirtualLock(const_cast<void*>(addr), len) != 0;
-#else
- return mlock(addr, len) == 0;
-#endif
-}
-
-bool MemoryPageLocker::Unlock(const void* addr, size_t len)
-{
-#ifdef WIN32
- return VirtualUnlock(const_cast<void*>(addr), len) != 0;
-#else
- return munlock(addr, len) == 0;
-#endif
-}
-
-LockedPageManager::LockedPageManager() : LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
-{
-}
diff --git a/src/support/pagelocker.h b/src/support/pagelocker.h
deleted file mode 100644
index 6b3979e551..0000000000
--- a/src/support/pagelocker.h
+++ /dev/null
@@ -1,177 +0,0 @@
-// 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_SUPPORT_PAGELOCKER_H
-#define BITCOIN_SUPPORT_PAGELOCKER_H
-
-#include "support/cleanse.h"
-
-#include <map>
-
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/once.hpp>
-
-/**
- * Thread-safe class to keep track of locked (ie, non-swappable) memory pages.
- *
- * Memory locks do not stack, that is, pages which have been locked several times by calls to mlock()
- * will be unlocked by a single call to munlock(). This can result in keying material ending up in swap when
- * those functions are used naively. This class simulates stacking memory locks by keeping a counter per page.
- *
- * @note By using a map from each page base address to lock count, this class is optimized for
- * small objects that span up to a few pages, mostly smaller than a page. To support large allocations,
- * something like an interval tree would be the preferred data structure.
- */
-template <class Locker>
-class LockedPageManagerBase
-{
-public:
- LockedPageManagerBase(size_t page_size) : page_size(page_size)
- {
- // Determine bitmask for extracting page from address
- assert(!(page_size & (page_size - 1))); // size must be power of two
- page_mask = ~(page_size - 1);
- }
-
- ~LockedPageManagerBase()
- {
- }
-
-
- // For all pages in affected range, increase lock count
- void LockRange(void* p, size_t size)
- {
- boost::mutex::scoped_lock lock(mutex);
- if (!size)
- return;
- const size_t base_addr = reinterpret_cast<size_t>(p);
- const size_t start_page = base_addr & page_mask;
- const size_t end_page = (base_addr + size - 1) & page_mask;
- for (size_t page = start_page; page <= end_page; page += page_size) {
- Histogram::iterator it = histogram.find(page);
- if (it == histogram.end()) // Newly locked page
- {
- locker.Lock(reinterpret_cast<void*>(page), page_size);
- histogram.insert(std::make_pair(page, 1));
- } else // Page was already locked; increase counter
- {
- it->second += 1;
- }
- }
- }
-
- // For all pages in affected range, decrease lock count
- void UnlockRange(void* p, size_t size)
- {
- boost::mutex::scoped_lock lock(mutex);
- if (!size)
- return;
- const size_t base_addr = reinterpret_cast<size_t>(p);
- const size_t start_page = base_addr & page_mask;
- const size_t end_page = (base_addr + size - 1) & page_mask;
- for (size_t page = start_page; page <= end_page; page += page_size) {
- Histogram::iterator it = histogram.find(page);
- assert(it != histogram.end()); // Cannot unlock an area that was not locked
- // Decrease counter for page, when it is zero, the page will be unlocked
- it->second -= 1;
- if (it->second == 0) // Nothing on the page anymore that keeps it locked
- {
- // Unlock page and remove the count from histogram
- locker.Unlock(reinterpret_cast<void*>(page), page_size);
- histogram.erase(it);
- }
- }
- }
-
- // Get number of locked pages for diagnostics
- int GetLockedPageCount()
- {
- boost::mutex::scoped_lock lock(mutex);
- return histogram.size();
- }
-
-private:
- Locker locker;
- boost::mutex mutex;
- size_t page_size, page_mask;
- // map of page base address to lock count
- typedef std::map<size_t, int> Histogram;
- Histogram histogram;
-};
-
-
-/**
- * OS-dependent memory page locking/unlocking.
- * Defined as policy class to make stubbing for test possible.
- */
-class MemoryPageLocker
-{
-public:
- /** Lock memory pages.
- * addr and len must be a multiple of the system page size
- */
- bool Lock(const void* addr, size_t len);
- /** Unlock memory pages.
- * addr and len must be a multiple of the system page size
- */
- bool Unlock(const void* addr, size_t len);
-};
-
-/**
- * Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in
- * std::allocator templates.
- *
- * Some implementations of the STL allocate memory in some constructors (i.e., see
- * MSVC's vector<T> implementation where it allocates 1 byte of memory in the allocator.)
- * Due to the unpredictable order of static initializers, we have to make sure the
- * LockedPageManager instance exists before any other STL-based objects that use
- * secure_allocator are created. So instead of having LockedPageManager also be
- * static-initialized, it is created on demand.
- */
-class LockedPageManager : public LockedPageManagerBase<MemoryPageLocker>
-{
-public:
- static LockedPageManager& Instance()
- {
- boost::call_once(LockedPageManager::CreateInstance, LockedPageManager::init_flag);
- return *LockedPageManager::_instance;
- }
-
-private:
- LockedPageManager();
-
- static void CreateInstance()
- {
- // Using a local static instance guarantees that the object is initialized
- // when it's first needed and also deinitialized after all objects that use
- // it are done with it. I can think of one unlikely scenario where we may
- // have a static deinitialization order/problem, but the check in
- // LockedPageManagerBase's destructor helps us detect if that ever happens.
- static LockedPageManager instance;
- LockedPageManager::_instance = &instance;
- }
-
- static LockedPageManager* _instance;
- static boost::once_flag init_flag;
-};
-
-//
-// Functions for directly locking/unlocking memory objects.
-// Intended for non-dynamically allocated structures.
-//
-template <typename T>
-void LockObject(const T& t)
-{
- LockedPageManager::Instance().LockRange((void*)(&t), sizeof(T));
-}
-
-template <typename T>
-void UnlockObject(const T& t)
-{
- memory_cleanse((void*)(&t), sizeof(T));
- LockedPageManager::Instance().UnlockRange((void*)(&t), sizeof(T));
-}
-
-#endif // BITCOIN_SUPPORT_PAGELOCKER_H
diff --git a/src/sync.cpp b/src/sync.cpp
index 641ed2c8ca..552682ab67 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -46,8 +46,6 @@ struct CLockLocation {
return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
}
- std::string MutexName() const { return mutexName; }
-
bool fTry;
private:
std::string mutexName;
@@ -77,52 +75,28 @@ boost::thread_specific_ptr<LockStack> lockstack;
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
- // We attempt to not assert on probably-not deadlocks by assuming that
- // a try lock will immediately have otherwise bailed if it had
- // failed to get the lock
- // We do this by, for the locks which triggered the potential deadlock,
- // in either lockorder, checking that the second of the two which is locked
- // is only a TRY_LOCK, ignoring locks if they are reentrant.
- bool firstLocked = false;
- bool secondLocked = false;
- bool onlyMaybeDeadlock = false;
-
LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
LogPrintf("Previous lock order was:\n");
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
if (i.first == mismatch.first) {
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) {
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)
@@ -134,21 +108,19 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
(*lockstack).push_back(std::make_pair(c, locklocation));
- if (!fTry) {
- BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) {
- if (i.first == c)
- break;
+ BOOST_FOREACH (const PAIRTYPE(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]);
}
}
diff --git a/src/sync.h b/src/sync.h
index 0c58fb6b4e..9274f50d8b 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -97,7 +97,6 @@ public:
}
};
-typedef CCriticalSection CDynamicCriticalSection;
/** Wrapped boost mutex: supports waiting but not recursive locking */
typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
@@ -171,7 +170,10 @@ public:
typedef CMutexLock<CCriticalSection> CCriticalBlock;
-#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
+#define PASTE(x, y) x ## y
+#define PASTE2(x, y) PASTE(x, y)
+
+#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
#define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
#define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
@@ -261,7 +263,6 @@ public:
grant.Release();
grant.sem = sem;
grant.fHaveGrant = fHaveGrant;
- sem = NULL;
fHaveGrant = false;
}
diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp
deleted file mode 100644
index 1b7d368e13..0000000000
--- a/src/test/Checkpoints_tests.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-//
-// Unit tests for block-chain checkpoints
-//
-
-#include "checkpoints.h"
-
-#include "uint256.h"
-#include "test/test_bitcoin.h"
-#include "chainparams.h"
-
-#include <boost/test/unit_test.hpp>
-
-using namespace std;
-
-BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup)
-
-BOOST_AUTO_TEST_CASE(sanity)
-{
- const CCheckpointData& checkpoints = Params(CBaseChainParams::MAIN).Checkpoints();
- BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate(checkpoints) >= 134444);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index a8c5f95ace..c62e6ae838 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -6,12 +6,13 @@
#include "chainparams.h"
#include "keystore.h"
-#include "main.h"
#include "net.h"
+#include "net_processing.h"
#include "pow.h"
#include "script/sign.h"
#include "serialize.h"
#include "util.h"
+#include "validation.h"
#include "test/test_bitcoin.h"
@@ -22,16 +23,16 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-// Tests this internal-to-main.cpp method:
-extern bool AddOrphanTx(const CTransaction& tx, NodeId peer);
+// 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);
struct COrphanTx {
- CTransaction tx;
+ CTransactionRef tx;
NodeId fromPeer;
+ int64_t nTimeExpire;
};
extern std::map<uint256, COrphanTx> mapOrphanTransactions;
-extern std::map<uint256, std::set<uint256> > mapOrphanTransactionsByPrev;
CService ip(uint32_t i)
{
@@ -40,72 +41,92 @@ CService ip(uint32_t i)
return CService(CNetAddr(s), Params().GetDefaultPort());
}
+static NodeId id = 0;
+
BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(DoS_banning)
{
- CNode::ClearBanned();
+ std::atomic<bool> interruptDummy(false);
+
+ connman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
+ CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, "", true);
+ dummyNode1.SetSendVersion(PROTOCOL_VERSION);
+ GetNodeSignals().InitializeNode(&dummyNode1, *connman);
dummyNode1.nVersion = 1;
+ dummyNode1.fSuccessfullyConnected = true;
Misbehaving(dummyNode1.GetId(), 100); // Should get banned
- SendMessages(&dummyNode1);
- BOOST_CHECK(CNode::IsBanned(addr1));
- BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
+ SendMessages(&dummyNode1, *connman, 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(INVALID_SOCKET, addr2, "", true);
+ CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, "", true);
+ dummyNode2.SetSendVersion(PROTOCOL_VERSION);
+ GetNodeSignals().InitializeNode(&dummyNode2, *connman);
dummyNode2.nVersion = 1;
+ dummyNode2.fSuccessfullyConnected = true;
Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2);
- BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
- BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
+ SendMessages(&dummyNode2, *connman, 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);
- BOOST_CHECK(CNode::IsBanned(addr2));
+ SendMessages(&dummyNode2, *connman, interruptDummy);
+ BOOST_CHECK(connman->IsBanned(addr2));
}
BOOST_AUTO_TEST_CASE(DoS_banscore)
{
- CNode::ClearBanned();
- mapArgs["-banscore"] = "111"; // because 11 is my favorite number
+ std::atomic<bool> interruptDummy(false);
+
+ connman->ClearBanned();
+ ForceSetArg("-banscore", "111"); // because 11 is my favorite number
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
+ CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, "", true);
+ dummyNode1.SetSendVersion(PROTOCOL_VERSION);
+ GetNodeSignals().InitializeNode(&dummyNode1, *connman);
dummyNode1.nVersion = 1;
+ dummyNode1.fSuccessfullyConnected = true;
Misbehaving(dummyNode1.GetId(), 100);
- SendMessages(&dummyNode1);
- BOOST_CHECK(!CNode::IsBanned(addr1));
+ SendMessages(&dummyNode1, *connman, interruptDummy);
+ BOOST_CHECK(!connman->IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 10);
- SendMessages(&dummyNode1);
- BOOST_CHECK(!CNode::IsBanned(addr1));
+ SendMessages(&dummyNode1, *connman, interruptDummy);
+ BOOST_CHECK(!connman->IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 1);
- SendMessages(&dummyNode1);
- BOOST_CHECK(CNode::IsBanned(addr1));
- mapArgs.erase("-banscore");
+ SendMessages(&dummyNode1, *connman, interruptDummy);
+ BOOST_CHECK(connman->IsBanned(addr1));
+ ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
}
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
- CNode::ClearBanned();
+ std::atomic<bool> interruptDummy(false);
+
+ connman->ClearBanned();
int64_t nStartTime = GetTime();
SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode(INVALID_SOCKET, addr, "", true);
+ CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, "", true);
+ dummyNode.SetSendVersion(PROTOCOL_VERSION);
+ GetNodeSignals().InitializeNode(&dummyNode, *connman);
dummyNode.nVersion = 1;
+ dummyNode.fSuccessfullyConnected = true;
Misbehaving(dummyNode.GetId(), 100);
- SendMessages(&dummyNode);
- BOOST_CHECK(CNode::IsBanned(addr));
+ SendMessages(&dummyNode, *connman, interruptDummy);
+ BOOST_CHECK(connman->IsBanned(addr));
SetMockTime(nStartTime+60*60);
- BOOST_CHECK(CNode::IsBanned(addr));
+ BOOST_CHECK(connman->IsBanned(addr));
SetMockTime(nStartTime+60*60*24+1);
- BOOST_CHECK(!CNode::IsBanned(addr));
+ BOOST_CHECK(!connman->IsBanned(addr));
}
-CTransaction RandomOrphan()
+CTransactionRef RandomOrphan()
{
std::map<uint256, COrphanTx>::iterator it;
it = mapOrphanTransactions.lower_bound(GetRandHash());
@@ -133,30 +154,30 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
- AddOrphanTx(tx, i);
+ AddOrphanTx(MakeTransactionRef(tx), i);
}
// ... and 50 that depend on other orphans:
for (int i = 0; i < 50; i++)
{
- CTransaction txPrev = RandomOrphan();
+ CTransactionRef txPrev = RandomOrphan();
CMutableTransaction tx;
tx.vin.resize(1);
tx.vin[0].prevout.n = 0;
- tx.vin[0].prevout.hash = txPrev.GetHash();
+ tx.vin[0].prevout.hash = txPrev->GetHash();
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
- SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL);
+ SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL);
- AddOrphanTx(tx, i);
+ AddOrphanTx(MakeTransactionRef(tx), i);
}
// This really-big orphan should be ignored:
for (int i = 0; i < 10; i++)
{
- CTransaction txPrev = RandomOrphan();
+ CTransactionRef txPrev = RandomOrphan();
CMutableTransaction tx;
tx.vout.resize(1);
@@ -166,15 +187,15 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
for (unsigned int j = 0; j < tx.vin.size(); j++)
{
tx.vin[j].prevout.n = j;
- tx.vin[j].prevout.hash = txPrev.GetHash();
+ tx.vin[j].prevout.hash = txPrev->GetHash();
}
- SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL);
+ SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL);
// Re-use same signature for other inputs
// (they don't have to be valid for this test)
for (unsigned int j = 1; j < tx.vin.size(); j++)
tx.vin[j].scriptSig = tx.vin[0].scriptSig;
- BOOST_CHECK(!AddOrphanTx(tx, i));
+ BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx), i));
}
// Test EraseOrphansFor:
@@ -192,7 +213,6 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
BOOST_CHECK(mapOrphanTransactions.size() <= 10);
LimitOrphanTxSize(0);
BOOST_CHECK(mapOrphanTransactions.empty());
- BOOST_CHECK(mapOrphanTransactionsByPrev.empty());
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/README.md b/src/test/README.md
index b2d6be14f1..eeb04c6ffa 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -1,26 +1,22 @@
-# Notes
-The sources in this directory are unit test cases. Boost includes a
-unit testing framework, and since bitcoin already uses boost, it makes
-sense to simply use this framework rather than require developers to
-configure some other framework (we want as few impediments to creating
-unit tests as possible).
+### Compiling/running unit tests
-The build system is setup to compile an executable called "test_bitcoin"
-that runs all of the unit tests. The main source file is called
-test_bitcoin.cpp, which simply includes other files that contain the
-actual unit tests (outside of a couple required preprocessor
-directives). The pattern is to create one test file for each class or
-source file for which you want to create unit tests. The file naming
-convention is "<source_filename>_tests.cpp" and such files should wrap
-their tests in a test suite called "<source_filename>_tests". For an
-examples of this pattern, examine uint160_tests.cpp and
-uint256_tests.cpp.
+Unit tests will be automatically compiled if dependencies were met in `./configure`
+and tests weren't explicitly disabled.
-Add the source files to /src/Makefile.test.include to add them to the build.
+After configuring, they can be run with `make check`.
-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/).
+To run the bitcoind tests manually, launch `src/test/test_bitcoin`.
+
+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
+implement new BOOST_AUTO_TEST_SUITE sections.
+
+To run the bitcoin-qt tests manually, launch `src/qt/test/test_bitcoin-qt`
+
+To add more bitcoin-qt tests, add them to the `src/qt/test/` directory and
+the `src/qt/test/test_main.cpp` file.
+
+### Running individual tests
test_bitcoin has some built-in command-line arguments; for
example, to run just the getarg_tests verbosely:
@@ -31,5 +27,26 @@ example, to run just the getarg_tests verbosely:
test_bitcoin --run_test=getarg_tests/doubledash
-Run test_bitcoin --help for the full list.
+Run `test_bitcoin --help` for the full list.
+### Note on adding test cases
+
+The sources in this directory are unit test cases. Boost includes a
+unit testing framework, and since bitcoin already uses boost, it makes
+sense to simply use this framework rather than require developers to
+configure some other framework (we want as few impediments to creating
+unit tests as possible).
+
+The build system is setup to compile an executable called `test_bitcoin`
+that runs all of the unit tests. The main source file is called
+test_bitcoin.cpp. To add a new unit test file to our test suite you need
+to add the file to `src/Makefile.test.include`. The pattern is to create
+one test file for each class or source file for which you want to create
+unit tests. The file naming convention is `<source_filename>_tests.cpp`
+and such files should wrap their tests in a test suite
+called `<source_filename>_tests`. For an example of this pattern,
+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/).
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index b6cec24b57..3812490ec0 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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 "addrman.h"
@@ -7,10 +7,9 @@
#include <boost/test/unit_test.hpp>
#include "hash.h"
+#include "netbase.h"
#include "random.h"
-using namespace std;
-
class CAddrManTest : public CAddrMan
{
uint64_t state;
@@ -25,7 +24,7 @@ public:
void MakeDeterministic()
{
nKey.SetNull();
- seed_insecure_rand(true);
+ insecure_rand = FastRandomContext(true);
}
int RandomInt(int nMax)
@@ -50,6 +49,30 @@ public:
}
};
+static CNetAddr ResolveIP(const char* ip)
+{
+ CNetAddr addr;
+ BOOST_CHECK_MESSAGE(LookupHost(ip, addr, false), strprintf("failed to resolve: %s", ip));
+ return addr;
+}
+
+static CNetAddr ResolveIP(std::string ip)
+{
+ return ResolveIP(ip.c_str());
+}
+
+static CService ResolveService(const char* ip, int port = 0)
+{
+ CService serv;
+ BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), strprintf("failed to resolve: %s:%i", ip, port));
+ return serv;
+}
+
+static CService ResolveService(std::string ip, int port = 0)
+{
+ return ResolveService(ip.c_str(), port);
+}
+
BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(addrman_simple)
@@ -59,38 +82,45 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
- CNetAddr source = CNetAddr("252.2.2.2");
+ 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.
- CService addr1 = CService("250.1.1.1", 8333);
- addrman.Add(CAddress(addr1, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 1);
+ // Test: Does Addrman::Add work as expected.
+ CService addr1 = ResolveService("250.1.1.1", 8333);
+ 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 = CService("250.1.1.1", 8333);
- addrman.Add(CAddress(addr1_dup, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 1);
+ CService addr1_dup = ResolveService("250.1.1.1", 8333);
+ 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
+ // Test: New table has one addr and we add a diff addr we should
// have two addrs.
- CService addr2 = CService("250.1.1.2", 8333);
- addrman.Add(CAddress(addr2, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 2);
+ CService addr2 = ResolveService("250.1.1.2", 8333);
+ BOOST_CHECK(addrman.Add(CAddress(addr2, NODE_NONE), source));
+ BOOST_CHECK_EQUAL(addrman.size(), 2);
- // 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_EQUAL(addrman.size(), 2);
}
BOOST_AUTO_TEST_CASE(addrman_ports)
@@ -100,28 +130,28 @@ BOOST_AUTO_TEST_CASE(addrman_ports)
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
- CNetAddr source = CNetAddr("252.2.2.2");
+ 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 = CService("250.1.1.1", 8333);
+ 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 = CService("250.1.1.1", 8334);
+ 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");
}
@@ -132,58 +162,59 @@ BOOST_AUTO_TEST_CASE(addrman_select)
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
- CNetAddr source = CNetAddr("252.2.2.2");
+ CNetAddr source = ResolveIP("252.2.2.2");
- // Test 9: Select from new with 1 addr in new.
- CService addr1 = CService("250.1.1.1", 8333);
+ // 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.
- CService addr2 = CService("250.3.1.1", 8333);
- CService addr3 = CService("250.3.2.2", 9999);
- CService addr4 = CService("250.3.3.3", 9999);
+ CService addr2 = ResolveService("250.3.1.1", 8333);
+ CService addr3 = ResolveService("250.3.2.2", 9999);
+ CService addr4 = ResolveService("250.3.3.3", 9999);
- addrman.Add(CAddress(addr2, NODE_NONE), CService("250.3.1.1", 8333));
- addrman.Add(CAddress(addr3, NODE_NONE), CService("250.3.1.1", 8333));
- addrman.Add(CAddress(addr4, NODE_NONE), CService("250.4.1.1", 8333));
+ addrman.Add(CAddress(addr2, NODE_NONE), ResolveService("250.3.1.1", 8333));
+ addrman.Add(CAddress(addr3, NODE_NONE), ResolveService("250.3.1.1", 8333));
+ addrman.Add(CAddress(addr4, NODE_NONE), ResolveService("250.4.1.1", 8333));
// Add three addresses to tried table.
- CService addr5 = CService("250.4.4.4", 8333);
- CService addr6 = CService("250.4.5.5", 7777);
- CService addr7 = CService("250.4.6.6", 8333);
+ CService addr5 = ResolveService("250.4.4.4", 8333);
+ CService addr6 = ResolveService("250.4.5.5", 7777);
+ CService addr7 = ResolveService("250.4.6.6", 8333);
- addrman.Add(CAddress(addr5, NODE_NONE), CService("250.3.1.1", 8333));
+ addrman.Add(CAddress(addr5, NODE_NONE), ResolveService("250.3.1.1", 8333));
addrman.Good(CAddress(addr5, NODE_NONE));
- addrman.Add(CAddress(addr6, NODE_NONE), CService("250.3.1.1", 8333));
+ addrman.Add(CAddress(addr6, NODE_NONE), ResolveService("250.3.1.1", 8333));
addrman.Good(CAddress(addr6, NODE_NONE));
- addrman.Add(CAddress(addr7, NODE_NONE), CService("250.1.1.3", 8333));
+ 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)
@@ -193,26 +224,26 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions)
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
- CNetAddr source = CNetAddr("252.2.2.2");
+ 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 = CService("250.1.1." + boost::to_string(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!
- CService addr1 = CService("250.1.1.18");
+ //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 = CService("250.1.1.19");
+ 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)
@@ -222,28 +253,27 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
- CNetAddr source = CNetAddr("252.2.2.2");
+ 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 = CService("250.1.1." + boost::to_string(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.
- BOOST_TEST_MESSAGE(addrman.size());
- BOOST_CHECK(addrman.size() == i);
+ //Test: No collision in tried table yet.
+ BOOST_CHECK_EQUAL(addrman.size(), i);
}
- //Test 16: tried table collision!
- CService addr1 = CService("250.1.1.80");
+ //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 = CService("250.1.1.81");
+ 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)
@@ -253,36 +283,33 @@ BOOST_AUTO_TEST_CASE(addrman_find)
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
- CAddress addr1 = CAddress(CService("250.1.2.1", 8333), NODE_NONE);
- CAddress addr2 = CAddress(CService("250.1.2.1", 9999), NODE_NONE);
- CAddress addr3 = CAddress(CService("251.255.2.1", 8333), NODE_NONE);
+ CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
+ CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
+ CAddress addr3 = CAddress(ResolveService("251.255.2.1", 8333), NODE_NONE);
- CNetAddr source1 = CNetAddr("250.1.2.1");
- CNetAddr source2 = CNetAddr("250.1.2.2");
+ CNetAddr source1 = ResolveIP("250.1.2.1");
+ CNetAddr source2 = ResolveIP("250.1.2.2");
addrman.Add(addr1, source1);
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)
@@ -292,19 +319,19 @@ BOOST_AUTO_TEST_CASE(addrman_create)
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
- CAddress addr1 = CAddress(CService("250.1.2.1", 8333), NODE_NONE);
- CNetAddr source1 = CNetAddr("250.1.2.1");
+ CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
+ CNetAddr source1 = ResolveIP("250.1.2.1");
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");
}
@@ -315,18 +342,18 @@ BOOST_AUTO_TEST_CASE(addrman_delete)
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
- CAddress addr1 = CAddress(CService("250.1.2.1", 8333), NODE_NONE);
- CNetAddr source1 = CNetAddr("250.1.2.1");
+ CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
+ CNetAddr source1 = ResolveIP("250.1.2.1");
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);
}
@@ -338,26 +365,26 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
// 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);
- vector<CAddress> vAddr1 = addrman.GetAddr();
- BOOST_CHECK(vAddr1.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
+ std::vector<CAddress> vAddr1 = addrman.GetAddr();
+ BOOST_CHECK_EQUAL(vAddr1.size(), 0);
- CAddress addr1 = CAddress(CService("250.250.2.1", 8333), NODE_NONE);
+ CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false
- CAddress addr2 = CAddress(CService("250.251.2.2", 9999), NODE_NONE);
+ CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
addr2.nTime = GetAdjustedTime();
- CAddress addr3 = CAddress(CService("251.252.2.3", 8333), NODE_NONE);
+ CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
addr3.nTime = GetAdjustedTime();
- CAddress addr4 = CAddress(CService("252.253.3.4", 8333), NODE_NONE);
+ CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
addr4.nTime = GetAdjustedTime();
- CAddress addr5 = CAddress(CService("252.254.4.5", 8333), NODE_NONE);
+ CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
addr5.nTime = GetAdjustedTime();
- CNetAddr source1 = CNetAddr("250.1.2.1");
- CNetAddr source2 = CNetAddr("250.2.3.3");
+ 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);
@@ -365,34 +392,33 @@ 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;
- string strAddr = boost::to_string(octet1) + "." + boost::to_string(octet2) + "." + boost::to_string(octet3) + ".23";
- CAddress addr = CAddress(CService(strAddr), NODE_NONE);
-
+ 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, CNetAddr(strAddr));
+ addrman.Add(addr, ResolveIP(strAddr));
if (i % 8 == 0)
addrman.Good(addr);
}
- vector<CAddress> vAddr = 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);
}
@@ -403,10 +429,10 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
- CAddress addr1 = CAddress(CService("250.1.1.1", 8333), NODE_NONE);
- CAddress addr2 = CAddress(CService("250.1.1.1", 9999), NODE_NONE);
+ CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
+ CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
- CNetAddr source1 = CNetAddr("250.1.1.1");
+ CNetAddr source1 = ResolveIP("250.1.1.1");
CAddrInfo info1 = CAddrInfo(addr1, source1);
@@ -415,42 +441,42 @@ 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);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
BOOST_CHECK(info1.GetTriedBucket(nKey1) != info2.GetTriedBucket(nKey1));
- set<int> buckets;
+ std::set<int> buckets;
for (int i = 0; i < 255; i++) {
CAddrInfo infoi = CAddrInfo(
- CAddress(CService("250.1.1." + boost::to_string(i)), NODE_NONE),
- CNetAddr("250.1.1." + boost::to_string(i)));
+ CAddress(ResolveService("250.1.1." + boost::to_string(i)), NODE_NONE),
+ ResolveIP("250.1.1." + boost::to_string(i)));
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++) {
CAddrInfo infoj = CAddrInfo(
- CAddress(CService("250." + boost::to_string(j) + ".1.1"), NODE_NONE),
- CNetAddr("250." + boost::to_string(j) + ".1.1"));
+ CAddress(ResolveService("250." + boost::to_string(j) + ".1.1"), NODE_NONE),
+ ResolveIP("250." + boost::to_string(j) + ".1.1"));
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)
@@ -460,62 +486,64 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
- CAddress addr1 = CAddress(CService("250.1.2.1", 8333), NODE_NONE);
- CAddress addr2 = CAddress(CService("250.1.2.1", 9999), NODE_NONE);
+ CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
+ CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
- CNetAddr source1 = CNetAddr("250.1.2.1");
+ CNetAddr source1 = ResolveIP("250.1.2.1");
CAddrInfo info1 = CAddrInfo(addr1, source1);
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));
- set<int> buckets;
+ std::set<int> buckets;
for (int i = 0; i < 255; i++) {
CAddrInfo infoi = CAddrInfo(
- CAddress(CService("250.1.1." + boost::to_string(i)), NODE_NONE),
- CNetAddr("250.1.1." + boost::to_string(i)));
+ CAddress(ResolveService("250.1.1." + boost::to_string(i)), NODE_NONE),
+ ResolveIP("250.1.1." + boost::to_string(i)));
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++) {
CAddrInfo infoj = CAddrInfo(CAddress(
- CService(
+ ResolveService(
boost::to_string(250 + (j / 255)) + "." + boost::to_string(j % 256) + ".1.1"), NODE_NONE),
- CNetAddr("251.4.1.1"));
+ ResolveIP("251.4.1.1"));
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);
buckets.clear();
for (int p = 0; p < 255; p++) {
CAddrInfo infoj = CAddrInfo(
- CAddress(CService("250.1.1.1"), NODE_NONE),
- CNetAddr("250." + boost::to_string(p) + ".1.1"));
+ CAddress(ResolveService("250.1.1.1"), NODE_NONE),
+ ResolveIP("250." + boost::to_string(p) + ".1.1"));
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);
}
-BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index 613f6c12d7..3f15a0dec1 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -11,110 +11,224 @@
BOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup)
-// Dummy memory page locker for platform independent tests
-static const void *last_lock_addr, *last_unlock_addr;
-static size_t last_lock_len, last_unlock_len;
-class TestLocker
+BOOST_AUTO_TEST_CASE(arena_tests)
{
-public:
- bool Lock(const void *addr, size_t len)
+ // Fake memory base address for testing
+ // without actually using memory.
+ void *synth_base = reinterpret_cast<void*>(0x08000000);
+ const size_t synth_size = 1024*1024;
+ Arena b(synth_base, synth_size, 16);
+ void *chunk = b.alloc(1000);
+#ifdef ARENA_DEBUG
+ b.walk();
+#endif
+ BOOST_CHECK(chunk != nullptr);
+ BOOST_CHECK(b.stats().used == 1008); // Aligned to 16
+ BOOST_CHECK(b.stats().total == synth_size); // Nothing has disappeared?
+ b.free(chunk);
+#ifdef ARENA_DEBUG
+ b.walk();
+#endif
+ BOOST_CHECK(b.stats().used == 0);
+ BOOST_CHECK(b.stats().free == synth_size);
+ try { // Test exception on double-free
+ b.free(chunk);
+ BOOST_CHECK(0);
+ } catch(std::runtime_error &)
{
- last_lock_addr = addr;
- last_lock_len = len;
- return true;
}
- bool Unlock(const void *addr, size_t len)
- {
- last_unlock_addr = addr;
- last_unlock_len = len;
- return true;
+
+ void *a0 = b.alloc(128);
+ void *a1 = b.alloc(256);
+ void *a2 = b.alloc(512);
+ BOOST_CHECK(b.stats().used == 896);
+ BOOST_CHECK(b.stats().total == synth_size);
+#ifdef ARENA_DEBUG
+ b.walk();
+#endif
+ b.free(a0);
+#ifdef ARENA_DEBUG
+ b.walk();
+#endif
+ BOOST_CHECK(b.stats().used == 768);
+ b.free(a1);
+ BOOST_CHECK(b.stats().used == 512);
+ void *a3 = b.alloc(128);
+#ifdef ARENA_DEBUG
+ b.walk();
+#endif
+ BOOST_CHECK(b.stats().used == 640);
+ b.free(a2);
+ BOOST_CHECK(b.stats().used == 128);
+ b.free(a3);
+ BOOST_CHECK(b.stats().used == 0);
+ BOOST_CHECK_EQUAL(b.stats().chunks_used, 0);
+ BOOST_CHECK(b.stats().total == synth_size);
+ BOOST_CHECK(b.stats().free == synth_size);
+ BOOST_CHECK_EQUAL(b.stats().chunks_free, 1);
+
+ std::vector<void*> addr;
+ BOOST_CHECK(b.alloc(0) == nullptr); // allocating 0 always returns nullptr
+#ifdef ARENA_DEBUG
+ b.walk();
+#endif
+ // Sweeping allocate all memory
+ for (int x=0; x<1024; ++x)
+ addr.push_back(b.alloc(1024));
+ BOOST_CHECK(b.stats().free == 0);
+ BOOST_CHECK(b.alloc(1024) == nullptr); // memory is full, this must return nullptr
+ BOOST_CHECK(b.alloc(0) == nullptr);
+ for (int x=0; x<1024; ++x)
+ b.free(addr[x]);
+ addr.clear();
+ BOOST_CHECK(b.stats().total == synth_size);
+ BOOST_CHECK(b.stats().free == synth_size);
+
+ // Now in the other direction...
+ for (int x=0; x<1024; ++x)
+ addr.push_back(b.alloc(1024));
+ for (int x=0; x<1024; ++x)
+ b.free(addr[1023-x]);
+ addr.clear();
+
+ // Now allocate in smaller unequal chunks, then deallocate haphazardly
+ // Not all the chunks will succeed allocating, but freeing nullptr is
+ // allowed so that is no problem.
+ for (int x=0; x<2048; ++x)
+ addr.push_back(b.alloc(x+1));
+ for (int x=0; x<2048; ++x)
+ b.free(addr[((x*23)%2048)^242]);
+ addr.clear();
+
+ // Go entirely wild: free and alloc interleaved,
+ // generate targets and sizes using pseudo-randomness.
+ for (int x=0; x<2048; ++x)
+ addr.push_back(0);
+ uint32_t s = 0x12345678;
+ for (int x=0; x<5000; ++x) {
+ int idx = s & (addr.size()-1);
+ if (s & 0x80000000) {
+ b.free(addr[idx]);
+ addr[idx] = 0;
+ } else if(!addr[idx]) {
+ addr[idx] = b.alloc((s >> 16) & 2047);
+ }
+ bool lsb = s & 1;
+ s >>= 1;
+ if (lsb)
+ s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0
}
-};
+ for (void *ptr: addr)
+ b.free(ptr);
+ addr.clear();
-BOOST_AUTO_TEST_CASE(test_LockedPageManagerBase)
+ BOOST_CHECK(b.stats().total == synth_size);
+ BOOST_CHECK(b.stats().free == synth_size);
+}
+
+/** Mock LockedPageAllocator for testing */
+class TestLockedPageAllocator: public LockedPageAllocator
{
- const size_t test_page_size = 4096;
- LockedPageManagerBase<TestLocker> lpm(test_page_size);
- size_t addr;
- last_lock_addr = last_unlock_addr = 0;
- last_lock_len = last_unlock_len = 0;
-
- /* Try large number of small objects */
- addr = 0;
- for(int i=0; i<1000; ++i)
- {
- lpm.LockRange(reinterpret_cast<void*>(addr), 33);
- addr += 33;
- }
- /* Try small number of page-sized objects, straddling two pages */
- addr = test_page_size*100 + 53;
- for(int i=0; i<100; ++i)
- {
- lpm.LockRange(reinterpret_cast<void*>(addr), test_page_size);
- addr += test_page_size;
- }
- /* Try small number of page-sized objects aligned to exactly one page */
- addr = test_page_size*300;
- for(int i=0; i<100; ++i)
- {
- lpm.LockRange(reinterpret_cast<void*>(addr), test_page_size);
- addr += test_page_size;
- }
- /* one very large object, straddling pages */
- lpm.LockRange(reinterpret_cast<void*>(test_page_size*600+1), test_page_size*500);
- BOOST_CHECK(last_lock_addr == reinterpret_cast<void*>(test_page_size*(600+500)));
- /* one very large object, page aligned */
- lpm.LockRange(reinterpret_cast<void*>(test_page_size*1200), test_page_size*500-1);
- BOOST_CHECK(last_lock_addr == reinterpret_cast<void*>(test_page_size*(1200+500-1)));
-
- BOOST_CHECK(lpm.GetLockedPageCount() == (
- (1000*33+test_page_size-1)/test_page_size + // small objects
- 101 + 100 + // page-sized objects
- 501 + 500)); // large objects
- BOOST_CHECK((last_lock_len & (test_page_size-1)) == 0); // always lock entire pages
- BOOST_CHECK(last_unlock_len == 0); // nothing unlocked yet
-
- /* And unlock again */
- addr = 0;
- for(int i=0; i<1000; ++i)
+public:
+ TestLockedPageAllocator(int count_in, int lockedcount_in): count(count_in), lockedcount(lockedcount_in) {}
+ void* AllocateLocked(size_t len, bool *lockingSuccess)
{
- lpm.UnlockRange(reinterpret_cast<void*>(addr), 33);
- addr += 33;
+ *lockingSuccess = false;
+ if (count > 0) {
+ --count;
+
+ if (lockedcount > 0) {
+ --lockedcount;
+ *lockingSuccess = true;
+ }
+
+ return reinterpret_cast<void*>(0x08000000 + (count<<24)); // Fake address, do not actually use this memory
+ }
+ return 0;
}
- addr = test_page_size*100 + 53;
- for(int i=0; i<100; ++i)
+ void FreeLocked(void* addr, size_t len)
{
- lpm.UnlockRange(reinterpret_cast<void*>(addr), test_page_size);
- addr += test_page_size;
}
- addr = test_page_size*300;
- for(int i=0; i<100; ++i)
+ size_t GetLimit()
{
- lpm.UnlockRange(reinterpret_cast<void*>(addr), test_page_size);
- addr += test_page_size;
+ return std::numeric_limits<size_t>::max();
}
- lpm.UnlockRange(reinterpret_cast<void*>(test_page_size*600+1), test_page_size*500);
- lpm.UnlockRange(reinterpret_cast<void*>(test_page_size*1200), test_page_size*500-1);
+private:
+ int count;
+ int lockedcount;
+};
- /* Check that everything is released */
- BOOST_CHECK(lpm.GetLockedPageCount() == 0);
+BOOST_AUTO_TEST_CASE(lockedpool_tests_mock)
+{
+ // Test over three virtual arenas, of which one will succeed being locked
+ std::unique_ptr<LockedPageAllocator> x(new TestLockedPageAllocator(3, 1));
+ LockedPool pool(std::move(x));
+ BOOST_CHECK(pool.stats().total == 0);
+ BOOST_CHECK(pool.stats().locked == 0);
- /* A few and unlocks of size zero (should have no effect) */
- addr = 0;
- for(int i=0; i<1000; ++i)
- {
- lpm.LockRange(reinterpret_cast<void*>(addr), 0);
- addr += 1;
- }
- BOOST_CHECK(lpm.GetLockedPageCount() == 0);
- addr = 0;
- for(int i=0; i<1000; ++i)
+ // Ensure unreasonable requests are refused without allocating anything
+ void *invalid_toosmall = pool.alloc(0);
+ BOOST_CHECK(invalid_toosmall == nullptr);
+ BOOST_CHECK(pool.stats().used == 0);
+ BOOST_CHECK(pool.stats().free == 0);
+ void *invalid_toobig = pool.alloc(LockedPool::ARENA_SIZE+1);
+ BOOST_CHECK(invalid_toobig == nullptr);
+ BOOST_CHECK(pool.stats().used == 0);
+ BOOST_CHECK(pool.stats().free == 0);
+
+ void *a0 = pool.alloc(LockedPool::ARENA_SIZE / 2);
+ BOOST_CHECK(a0);
+ BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);
+ void *a1 = pool.alloc(LockedPool::ARENA_SIZE / 2);
+ BOOST_CHECK(a1);
+ void *a2 = pool.alloc(LockedPool::ARENA_SIZE / 2);
+ BOOST_CHECK(a2);
+ void *a3 = pool.alloc(LockedPool::ARENA_SIZE / 2);
+ BOOST_CHECK(a3);
+ void *a4 = pool.alloc(LockedPool::ARENA_SIZE / 2);
+ BOOST_CHECK(a4);
+ void *a5 = pool.alloc(LockedPool::ARENA_SIZE / 2);
+ BOOST_CHECK(a5);
+ // We've passed a count of three arenas, so this allocation should fail
+ void *a6 = pool.alloc(16);
+ BOOST_CHECK(!a6);
+
+ pool.free(a0);
+ pool.free(a2);
+ pool.free(a4);
+ pool.free(a1);
+ pool.free(a3);
+ pool.free(a5);
+ BOOST_CHECK(pool.stats().total == 3*LockedPool::ARENA_SIZE);
+ BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);
+ BOOST_CHECK(pool.stats().used == 0);
+}
+
+// These tests used the live LockedPoolManager object, this is also used
+// by other tests so the conditions are somewhat less controllable and thus the
+// tests are somewhat more error-prone.
+BOOST_AUTO_TEST_CASE(lockedpool_tests_live)
+{
+ LockedPoolManager &pool = LockedPoolManager::Instance();
+ LockedPool::Stats initial = pool.stats();
+
+ void *a0 = pool.alloc(16);
+ BOOST_CHECK(a0);
+ // Test reading and writing the allocated memory
+ *((uint32_t*)a0) = 0x1234;
+ BOOST_CHECK(*((uint32_t*)a0) == 0x1234);
+
+ pool.free(a0);
+ try { // Test exception on double-free
+ pool.free(a0);
+ BOOST_CHECK(0);
+ } catch(std::runtime_error &)
{
- lpm.UnlockRange(reinterpret_cast<void*>(addr), 0);
- addr += 1;
}
- BOOST_CHECK(lpm.GetLockedPageCount() == 0);
- BOOST_CHECK((last_unlock_len & (test_page_size-1)) == 0); // always unlock entire pages
+ // If more than one new arena was allocated for the above tests, something is wrong
+ BOOST_CHECK(pool.stats().total <= (initial.total + LockedPool::ARENA_SIZE));
+ // Usage must be back to where it started
+ BOOST_CHECK(pool.stats().used == initial.used);
}
BOOST_AUTO_TEST_SUITE_END()
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 53ab7e95ee..45ae7d4636 100644
--- a/src/test/arith_uint256_tests.cpp
+++ b/src/test/arith_uint256_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality
BOOST_CHECK( (R1L & arith_uint256("0xffffffffffffffff")) == arith_uint256(R1LLow64));
BOOST_CHECK(ZeroL == arith_uint256(0));
BOOST_CHECK(OneL == arith_uint256(1));
- BOOST_CHECK(arith_uint256("0xffffffffffffffff") = arith_uint256(0xffffffffffffffffULL));
+ BOOST_CHECK(arith_uint256("0xffffffffffffffff") == arith_uint256(0xffffffffffffffffULL));
// Assignment (from base_uint)
arith_uint256 tmpL = ~ZeroL; BOOST_CHECK(tmpL == ~ZeroL);
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 01eb2aee9e..6cd998990b 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());
std::string base58string = test[1].get_str();
BOOST_CHECK_MESSAGE(
- EncodeBase58(begin_ptr(sourcedata), end_ptr(sourcedata)) == base58string,
+ EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size()) == base58string,
strTest);
}
}
@@ -121,7 +121,6 @@ public:
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)));
- std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
SelectParams(CBaseChainParams::MAIN);
@@ -179,7 +178,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
- std::vector<unsigned char> result;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
@@ -247,7 +245,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
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
- std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
diff --git a/src/test/bctest.py b/src/test/bctest.py
deleted file mode 100644
index 8105b87ffa..0000000000
--- a/src/test/bctest.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2014 BitPay, Inc.
-# 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
-
-def bctest(testDir, testObj, exeext):
-
- execprog = testObj['exec'] + exeext
- execargs = testObj['args']
- execrun = [execprog] + execargs
- stdinCfg = None
- inputData = None
- if "input" in testObj:
- filename = testDir + "/" + testObj['input']
- inputData = open(filename).read()
- stdinCfg = subprocess.PIPE
-
- outputFn = None
- outputData = None
- if "output_cmp" in testObj:
- outputFn = testObj['output_cmp']
- outputData = open(testDir + "/" + outputFn).read()
- proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True)
- try:
- outs = proc.communicate(input=inputData)
- except OSError:
- print("OSError, Failed to execute " + execprog)
- sys.exit(1)
-
- if outputData and (outs[0] != outputData):
- print("Output data mismatch for " + outputFn)
- sys.exit(1)
-
- wantRC = 0
- if "return_code" in testObj:
- wantRC = testObj['return_code']
- if proc.returncode != wantRC:
- print("Return code mismatch for " + outputFn)
- sys.exit(1)
-
-def bctester(testDir, input_basename, buildenv):
- input_filename = testDir + "/" + input_basename
- raw_data = open(input_filename).read()
- input_data = json.loads(raw_data)
-
- for testObj in input_data:
- bctest(testDir, testObj, buildenv.exeext)
-
- sys.exit(0)
-
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 7f1c2a32dd..c148ad6d82 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -78,6 +78,15 @@ 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;
@@ -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 95dd3e81b4..0000000000
--- a/src/test/bitcoin-util-test.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/python
-# Copyright 2014 BitPay, Inc.
-# 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 bctest
-import buildenv
-
-if __name__ == '__main__':
- bctest.bctester(os.environ["srcdir"] + "/test/data",
- "bitcoin-util-test.json",buildenv)
-
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 3884bf3fe3..9e4a56919d 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -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) {}
};
@@ -26,21 +28,21 @@ static CBlock BuildBlockTestCase() {
tx.vout[0].nValue = 42;
block.vtx.resize(3);
- block.vtx[0] = tx;
+ block.vtx[0] = MakeTransactionRef(tx);
block.nVersion = 42;
block.hashPrevBlock = GetRandHash();
block.nBits = 0x207fffff;
tx.vin[0].prevout.hash = GetRandHash();
tx.vin[0].prevout.n = 0;
- block.vtx[1] = tx;
+ 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.n = 0;
}
- block.vtx[2] = tx;
+ block.vtx[2] = MakeTransactionRef(tx);
bool mutated;
block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);
@@ -55,16 +57,16 @@ static CBlock BuildBlockTestCase() {
BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
- pool.addUnchecked(block.vtx[2].GetHash(), entry.FromTx(block.vtx[2]));
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+ pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
// Do a simple ShortTxIDs RT
{
- CBlockHeaderAndShortTxIDs shortIDs(block);
+ CBlockHeaderAndShortTxIDs shortIDs(block, true);
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << shortIDs;
@@ -73,29 +75,35 @@ 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));
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
- std::list<CTransaction> removed;
- pool.removeRecursive(block.vtx[2], removed);
- BOOST_CHECK_EQUAL(removed.size(), 1);
+ size_t poolSize = pool.size();
+ pool.removeRecursive(*block.vtx[2]);
+ BOOST_CHECK_EQUAL(pool.size(), poolSize - 1);
CBlock block2;
- std::vector<CTransaction> vtx_missing;
- BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_INVALID); // No transactions
+ {
+ PartiallyDownloadedBlock tmp = partialBlock;
+ BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_INVALID); // No transactions
+ partialBlock = tmp;
+ }
- vtx_missing.push_back(block.vtx[2]); // Wrong transaction
- partialBlock.FillBlock(block2, vtx_missing); // Current implementation doesn't check txn here, but don't require that
+ // Wrong transaction
+ {
+ PartiallyDownloadedBlock tmp = partialBlock;
+ partialBlock.FillBlock(block2, {block.vtx[2]}); // Current implementation doesn't check txn here, but don't require that
+ partialBlock = tmp;
+ }
bool mutated;
BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));
- vtx_missing[0] = block.vtx[1];
CBlock block3;
- BOOST_CHECK(partialBlock.FillBlock(block3, vtx_missing) == READ_STATUS_OK);
+ BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[1]}) == READ_STATUS_OK);
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString());
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());
BOOST_CHECK(!mutated);
@@ -116,7 +124,7 @@ public:
stream >> *this;
}
TestHeaderAndShortIDs(const CBlock& block) :
- TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block)) {}
+ TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block, true)) {}
uint64_t GetShortID(const uint256& txhash) const {
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
@@ -129,7 +137,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(header);
READWRITE(nonce);
size_t shorttxids_size = shorttxids.size();
@@ -148,12 +156,14 @@ public:
BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
- pool.addUnchecked(block.vtx[2].GetHash(), entry.FromTx(block.vtx[2]));
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+ pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+
+ uint256 txhash;
// Test with pre-forwarding tx 1, but not coinbase
{
@@ -161,8 +171,8 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
shortIDs.prefilledtxn.resize(1);
shortIDs.prefilledtxn[0] = {1, block.vtx[1]};
shortIDs.shorttxids.resize(2);
- shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0].GetHash());
- shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2].GetHash());
+ shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetHash());
+ shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetHash());
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << shortIDs;
@@ -171,42 +181,55 @@ 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));
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
CBlock block2;
- std::vector<CTransaction> vtx_missing;
- BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_INVALID); // No transactions
+ {
+ PartiallyDownloadedBlock tmp = partialBlock;
+ BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_INVALID); // No transactions
+ partialBlock = tmp;
+ }
- vtx_missing.push_back(block.vtx[1]); // Wrong transaction
- partialBlock.FillBlock(block2, vtx_missing); // Current implementation doesn't check txn here, but don't require that
+ // Wrong transaction
+ {
+ PartiallyDownloadedBlock tmp = partialBlock;
+ partialBlock.FillBlock(block2, {block.vtx[1]}); // Current implementation doesn't check txn here, but don't require that
+ partialBlock = tmp;
+ }
bool mutated;
BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));
- vtx_missing[0] = block.vtx[0];
CBlock block3;
- BOOST_CHECK(partialBlock.FillBlock(block3, vtx_missing) == READ_STATUS_OK);
+ PartiallyDownloadedBlock partialBlockCopy = partialBlock;
+ BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[0]}) == READ_STATUS_OK);
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString());
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());
BOOST_CHECK(!mutated);
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
+ txhash = block.vtx[2]->GetHash();
+ block.vtx.clear();
+ block2.vtx.clear();
+ block3.vtx.clear();
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); // + 1 because of partialBlockCopy.
}
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
}
BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
- pool.addUnchecked(block.vtx[1].GetHash(), entry.FromTx(block.vtx[1]));
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+ pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1]));
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+
+ uint256 txhash;
// Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool
{
@@ -215,7 +238,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
shortIDs.prefilledtxn[0] = {0, block.vtx[0]};
shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; // id == 1 as it is 1 after index 1
shortIDs.shorttxids.resize(1);
- shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1].GetHash());
+ shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetHash());
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << shortIDs;
@@ -224,29 +247,32 @@ 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));
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
CBlock block2;
- std::vector<CTransaction> vtx_missing;
- BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK);
+ PartiallyDownloadedBlock partialBlockCopy = partialBlock;
+ BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_OK);
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
bool mutated;
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
BOOST_CHECK(!mutated);
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
+ txhash = block.vtx[1]->GetHash();
+ block.vtx.clear();
+ block2.vtx.clear();
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); // + 1 because of partialBlockCopy.
}
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
}
BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
CMutableTransaction coinbase;
coinbase.vin.resize(1);
coinbase.vin[0].scriptSig.resize(10);
@@ -255,7 +281,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
CBlock block;
block.vtx.resize(1);
- block.vtx[0] = coinbase;
+ block.vtx[0] = MakeTransactionRef(std::move(coinbase));
block.nVersion = 42;
block.hashPrevBlock = GetRandHash();
block.nBits = 0x207fffff;
@@ -267,7 +293,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
// Test simple header round-trip with only coinbase
{
- CBlockHeaderAndShortTxIDs shortIDs(block);
+ CBlockHeaderAndShortTxIDs shortIDs(block, false);
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << shortIDs;
@@ -276,14 +302,13 @@ 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;
- std::vector<CTransaction> vtx_missing;
+ std::vector<CTransactionRef> vtx_missing;
BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK);
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
- bool mutated;
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
BOOST_CHECK(!mutated);
}
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 042fad42da..27bc92d670 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -21,8 +21,6 @@
#include <boost/test/unit_test.hpp>
#include <boost/tuple/tuple.hpp>
-using namespace std;
-
BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize)
@@ -30,30 +28,30 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize)
CBloomFilter filter(3, 0.01, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8"));
- BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter doesn't contain just-inserted object!");
+ BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter doesn't contain just-inserted object!");
// One bit different in first byte
- BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter contains something it shouldn't!");
+ BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter contains something it shouldn't!");
filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee"));
- BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "BloomFilter doesn't contain just-inserted object (2)!");
+ BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "Bloom filter doesn't contain just-inserted object (2)!");
filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5"));
- BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "BloomFilter doesn't contain just-inserted object (3)!");
+ BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "Bloom filter doesn't contain just-inserted object (3)!");
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
- filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION);
+ stream << filter;
- vector<unsigned char> vch = ParseHex("03614e9b050000000000000001");
- vector<char> expected(vch.size());
+ std::vector<unsigned char> vch = ParseHex("03614e9b050000000000000001");
+ std::vector<char> expected(vch.size());
for (unsigned int i = 0; i < vch.size(); i++)
expected[i] = (char)vch[i];
BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end());
- BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter doesn't contain just-inserted object!");
+ BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter doesn't contain just-inserted object!");
filter.clear();
- BOOST_CHECK_MESSAGE( !filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter should be empty!");
+ BOOST_CHECK_MESSAGE( !filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter should be empty!");
}
BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak)
@@ -62,21 +60,21 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak)
CBloomFilter filter(3, 0.01, 2147483649UL, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8"));
- BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter doesn't contain just-inserted object!");
+ BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter doesn't contain just-inserted object!");
// One bit different in first byte
- BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "BloomFilter contains something it shouldn't!");
+ BOOST_CHECK_MESSAGE(!filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter contains something it shouldn't!");
filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee"));
- BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "BloomFilter doesn't contain just-inserted object (2)!");
+ BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "Bloom filter doesn't contain just-inserted object (2)!");
filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5"));
- BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "BloomFilter doesn't contain just-inserted object (3)!");
+ BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "Bloom filter doesn't contain just-inserted object (3)!");
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
- filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION);
+ stream << filter;
- vector<unsigned char> vch = ParseHex("03ce4299050000000100008001");
- vector<char> expected(vch.size());
+ std::vector<unsigned char> vch = ParseHex("03ce4299050000000100008001");
+ std::vector<char> expected(vch.size());
for (unsigned int i = 0; i < vch.size(); i++)
expected[i] = (char)vch[i];
@@ -86,24 +84,24 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak)
BOOST_AUTO_TEST_CASE(bloom_create_insert_key)
{
- string strSecret = string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C");
+ std::string strSecret = std::string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C");
CBitcoinSecret vchSecret;
BOOST_CHECK(vchSecret.SetString(strSecret));
CKey key = vchSecret.GetKey();
CPubKey pubkey = key.GetPubKey();
- vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());
+ std::vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());
CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL);
filter.insert(vchPubKey);
uint160 hash = pubkey.GetID();
- filter.insert(vector<unsigned char>(hash.begin(), hash.end()));
+ filter.insert(std::vector<unsigned char>(hash.begin(), hash.end()));
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
- filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION);
+ stream << filter;
- vector<unsigned char> vch = ParseHex("038fc16b080000000000000001");
- vector<char> expected(vch.size());
+ std::vector<unsigned char> vch = ParseHex("038fc16b080000000000000001");
+ std::vector<char> expected(vch.size());
for (unsigned int i = 0; i < vch.size(); i++)
expected[i] = (char)vch[i];
@@ -114,16 +112,14 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key)
BOOST_AUTO_TEST_CASE(bloom_match)
{
// Random real transaction (b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b)
- CTransaction tx;
CDataStream stream(ParseHex("01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000"), SER_DISK, CLIENT_VERSION);
- stream >> tx;
+ CTransaction tx(deserialize, stream);
// and one which spends it (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436)
unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00};
- vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
+ std::vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
CDataStream spendStream(vch, SER_DISK, CLIENT_VERSION);
- CTransaction spendingTx;
- spendStream >> spendingTx;
+ CTransaction spendingTx(deserialize, spendStream);
CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(uint256S("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"));
@@ -158,7 +154,7 @@ BOOST_AUTO_TEST_CASE(bloom_match)
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
COutPoint prevOutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
{
- vector<unsigned char> data(32 + sizeof(unsigned int));
+ std::vector<unsigned char> data(32 + sizeof(unsigned int));
memcpy(&data[0], prevOutPoint.hash.begin(), 32);
memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int));
filter.insert(data);
@@ -198,13 +194,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_1)
BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
- pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
+ std::pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8);
- vector<uint256> vMatched;
- vector<unsigned int> vIndex;
+ std::vector<uint256> vMatched;
+ std::vector<unsigned int> vIndex;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
@@ -244,13 +240,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_2)
BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
- pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
+ std::pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
- vector<uint256> vMatched;
- vector<unsigned int> vIndex;
+ std::vector<uint256> vMatched;
+ std::vector<unsigned int> vIndex;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
@@ -299,13 +295,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none)
BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
- pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
+ std::pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"));
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
- vector<uint256> vMatched;
- vector<unsigned int> vIndex;
+ std::vector<uint256> vMatched;
+ std::vector<unsigned int> vIndex;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
@@ -355,8 +351,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize)
BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5"));
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0);
- vector<uint256> vMatched;
- vector<unsigned int> vIndex;
+ std::vector<uint256> vMatched;
+ std::vector<unsigned int> vIndex;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
@@ -365,8 +361,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize)
CDataStream merkleStream(SER_NETWORK, PROTOCOL_VERSION);
merkleStream << merkleBlock;
- vector<unsigned char> vch = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101");
- vector<char> expected(vch.size());
+ std::vector<unsigned char> vch = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101");
+ std::vector<char> expected(vch.size());
for (unsigned int i = 0; i < vch.size(); i++)
expected[i] = (char)vch[i];
@@ -390,13 +386,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_4)
BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
- pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
+ std::pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154"));
BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6);
- vector<uint256> vMatched;
- vector<unsigned int> vIndex;
+ std::vector<uint256> vMatched;
+ std::vector<unsigned int> vIndex;
BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot);
BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size());
for (unsigned int i = 0; i < vMatched.size(); i++)
diff --git a/src/test/bswap_tests.cpp b/src/test/bswap_tests.cpp
new file mode 100644
index 0000000000..7b3134d327
--- /dev/null
+++ b/src/test/bswap_tests.cpp
@@ -0,0 +1,26 @@
+// Copyright (c) 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 "compat/byteswap.h"
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(bswap_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(bswap_tests)
+{
+ // Sibling in bitcoin/src/qt/test/compattests.cpp
+ uint16_t u1 = 0x1234;
+ uint32_t u2 = 0x56789abc;
+ uint64_t u3 = 0xdef0123456789abc;
+ uint16_t e1 = 0x3412;
+ uint32_t e2 = 0xbc9a7856;
+ uint64_t e3 = 0xbc9a78563412f0de;
+ BOOST_CHECK(bswap_16(u1) == e1);
+ BOOST_CHECK(bswap_32(u2) == e2);
+ BOOST_CHECK(bswap_64(u3) == e3);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/buildenv.py.in b/src/test/buildenv.py.in
deleted file mode 100644
index 1618bdeb76..0000000000
--- a/src/test/buildenv.py.in
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/usr/bin/python
-exeext="@EXEEXT@"
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
new file mode 100644
index 0000000000..287395c6c6
--- /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) GetRand(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)GetRand(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 = GetRand(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 = GetRand(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 = GetRand(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;
+ bool has_lock {false};
+ bool has_tried {false};
+ bool done {false};
+ bool done_ack {false};
+ std::condition_variable cv;
+ {
+ 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 e692326559..31ed1a50b9 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -1,14 +1,15 @@
-// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Copyright (c) 2014-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 "coins.h"
-#include "random.h"
#include "script/standard.h"
#include "uint256.h"
+#include "undo.h"
#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
-#include "main.h"
+#include "test/test_random.h"
+#include "validation.h"
#include "consensus/validation.h"
#include <vector>
@@ -16,6 +17,9 @@
#include <boost/test/unit_test.hpp>
+bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out);
+void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
+
namespace
{
class CCoinsViewTest : public CCoinsView
@@ -68,7 +72,7 @@ public:
class CCoinsViewCacheTest : public CCoinsViewCache
{
public:
- CCoinsViewCacheTest(CCoinsView* base) : CCoinsViewCache(base) {}
+ CCoinsViewCacheTest(CCoinsView* _base) : CCoinsViewCache(_base) {}
void SelfTest() const
{
@@ -80,6 +84,8 @@ public:
BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret);
}
+ CCoinsMap& map() { return cacheCoins; }
+ size_t& usage() { return cachedCoinsUsage; }
};
}
@@ -211,6 +217,22 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
BOOST_CHECK(missed_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();
+ }
+ std::map<uint256, TxData>::iterator txdit = alltxs.find(*txIt);
+ assert(txdit != alltxs.end());
+ return txdit->second;
+}
+
+
// This test is similar to the previous test
// except the emphasis is on testing the functionality of UpdateCoins
// random txs are created and UpdateCoins is used to update the cache stack
@@ -227,77 +249,139 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
std::vector<CCoinsViewCacheTest*> stack; // A stack of CCoinsViewCaches on top.
stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache.
- // Track the txids we've used and whether they have been spent or not
- std::map<uint256, CAmount> coinbaseids;
- std::set<uint256> alltxids;
+ // 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;
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
- {
+ uint32_t randiter = insecure_rand();
+
+ // 19/20 txs add a new transaction
+ if (randiter % 20 < 19) {
CMutableTransaction tx;
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;
- // 1/10 times create a coinbase
- if (insecure_rand() % 10 == 0 || coinbaseids.size() < 10) {
- // 1/100 times create a duplicate coinbase
+ // 2/20 times create a new coinbase
+ if (randiter % 20 < 2 || coinbaseids.size() < 10) {
+ // 1/10 of those times create a duplicate coinbase
if (insecure_rand() % 10 == 0 && coinbaseids.size()) {
- std::map<uint256, CAmount>::iterator coinbaseIt = coinbaseids.lower_bound(GetRandHash());
- if (coinbaseIt == coinbaseids.end()) {
- coinbaseIt = coinbaseids.begin();
- }
- //Use same random value to have same hash and be a true duplicate
- tx.vout[0].nValue = coinbaseIt->second;
- assert(tx.GetHash() == coinbaseIt->first);
- duplicateids.insert(coinbaseIt->first);
+ TxData &txd = FindRandomFrom(coinbaseids);
+ // Reuse the exact same coinbase
+ tx = std::get<0>(txd);
+ // shouldn't be available for reconnection if its been duplicated
+ disconnectedids.erase(tx.GetHash());
+
+ duplicateids.insert(tx.GetHash());
}
else {
- coinbaseids[tx.GetHash()] = tx.vout[0].nValue;
+ coinbaseids.insert(tx.GetHash());
}
assert(CTransaction(tx).IsCoinBase());
}
- // 9/10 times create a regular tx
+
+ // 17/20 times reconnect previous or add a regular tx
else {
+
uint256 prevouthash;
- // equally likely to spend coinbase or non coinbase
- std::set<uint256>::iterator txIt = alltxids.lower_bound(GetRandHash());
- if (txIt == alltxids.end()) {
- txIt = alltxids.begin();
+ // 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());
+ 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())) {
+ assert(CTransaction(tx).IsCoinBase());
+ assert(duplicateids.count(tx.GetHash()));
+ }
+ disconnectedids.erase(tx.GetHash());
}
- prevouthash = *txIt;
- // Construct the tx to spend the coins of prevouthash
- tx.vin[0].prevout.hash = prevouthash;
- tx.vin[0].prevout.n = 0;
+ // 16/20 times create a regular tx
+ else {
+ TxData &txd = FindRandomFrom(utxoset);
+ prevouthash = std::get<0>(txd).GetHash();
+ // Construct the tx to spend the coins of prevouthash
+ tx.vin[0].prevout.hash = prevouthash;
+ tx.vin[0].prevout.n = 0;
+ 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];
// Update the expected result of prevouthash to know these coins are spent
- CCoins& oldcoins = result[prevouthash];
- oldcoins.Clear();
+ result[prevouthash].Clear();
- // It is of particular importance here that once we spend a coinbase tx hash
- // it is no longer available to be duplicated (or spent again)
- // BIP 34 in conjunction with enforcing BIP 30 (at least until BIP 34 was active)
- // results in the fact that no coinbases were duplicated after they were already spent
- alltxids.erase(prevouthash);
- coinbaseids.erase(prevouthash);
+ utxoset.erase(prevouthash);
// 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))
spent_a_duplicate_coinbase = true;
- assert(!CTransaction(tx).IsCoinBase());
}
- // Track this tx to possibly spend later
- alltxids.insert(tx.GetHash());
-
// Update the expected result to know about the new output coins
- CCoins &coins = result[tx.GetHash()];
- coins.FromTx(tx, height);
+ result[tx.GetHash()].FromTx(tx, height);
+
+ // 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());
+
+ // 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);
- UpdateCoins(tx, *(stack.back()), height);
+ CTransaction &tx = std::get<0>(txd);
+ CTxUndo &undo = std::get<1>(txd);
+ CCoins &origcoins = std::get<2>(txd);
+
+ uint256 undohash = tx.GetHash();
+
+ // Update the expected result
+ // Remove new outputs
+ result[undohash].Clear();
+ // If not coinbase restore prevout
+ if (!tx.IsCoinBase()) {
+ result[tx.vin[0].prevout.hash] = origcoins;
+ }
+
+ // Disconnect the tx from the current UTXO
+ // See code in DisconnectBlock
+ // remove outputs
+ {
+ CCoinsModifier outs = stack.back()->ModifyCoins(undohash);
+ outs->Clear();
+ }
+ // restore inputs
+ if (!tx.IsCoinBase()) {
+ const COutPoint &out = tx.vin[0].prevout;
+ const CTxInUndo &undoin = undo.vprevout[0];
+ ApplyTxInUndo(undoin, *(stack.back()), out);
+ }
+ // Store as a candidate for reconnection
+ disconnectedids.insert(undohash);
+
+ // Update the utxoset
+ utxoset.erase(undohash);
+ if (!tx.IsCoinBase())
+ utxoset.insert(tx.vin[0].prevout.hash);
}
// Once every 1000 iterations and at the end, verify the full cache.
@@ -306,9 +390,9 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
const CCoins* coins = stack.back()->AccessCoins(it->first);
if (coins) {
BOOST_CHECK(*coins == it->second);
- } else {
+ } else {
BOOST_CHECK(it->second.IsPruned());
- }
+ }
}
}
@@ -332,7 +416,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
tip = stack.back();
}
stack.push_back(new CCoinsViewCacheTest(tip));
- }
+ }
}
}
@@ -415,4 +499,378 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
}
}
+const static uint256 TXID;
+const static CAmount PRUNED = -1;
+const static CAmount ABSENT = -2;
+const static CAmount FAIL = -3;
+const static CAmount VALUE1 = 100;
+const static CAmount VALUE2 = 200;
+const static CAmount VALUE3 = 300;
+const static char DIRTY = CCoinsCacheEntry::DIRTY;
+const static char FRESH = CCoinsCacheEntry::FRESH;
+const static char NO_ENTRY = -1;
+
+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)
+{
+ assert(value != ABSENT);
+ coins.Clear();
+ assert(coins.IsPruned());
+ if (value != PRUNED) {
+ coins.vout.emplace_back();
+ coins.vout.back().nValue = value;
+ assert(!coins.IsPruned());
+ }
+}
+
+size_t InsertCoinsMapEntry(CCoinsMap& map, CAmount value, char flags)
+{
+ if (value == ABSENT) {
+ assert(flags == NO_ENTRY);
+ return 0;
+ }
+ assert(flags != NO_ENTRY);
+ CCoinsCacheEntry entry;
+ entry.flags = flags;
+ SetCoinsValue(value, entry.coins);
+ auto inserted = map.emplace(TXID, std::move(entry));
+ assert(inserted.second);
+ return inserted.first->second.coins.DynamicMemoryUsage();
+}
+
+void GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags)
+{
+ auto it = map.find(TXID);
+ if (it == map.end()) {
+ value = ABSENT;
+ flags = NO_ENTRY;
+ } else {
+ if (it->second.coins.IsPruned()) {
+ assert(it->second.coins.vout.size() == 0);
+ value = PRUNED;
+ } else {
+ assert(it->second.coins.vout.size() == 1);
+ value = it->second.coins.vout[0].nValue;
+ }
+ flags = it->second.flags;
+ assert(flags != NO_ENTRY);
+ }
+}
+
+void WriteCoinsViewEntry(CCoinsView& view, CAmount value, char flags)
+{
+ CCoinsMap map;
+ InsertCoinsMapEntry(map, value, flags);
+ view.BatchWrite(map, {});
+}
+
+class SingleEntryCacheTest
+{
+public:
+ SingleEntryCacheTest(CAmount base_value, CAmount cache_value, char cache_flags)
+ {
+ WriteCoinsViewEntry(base, base_value, base_value == ABSENT ? NO_ENTRY : DIRTY);
+ cache.usage() += InsertCoinsMapEntry(cache.map(), cache_value, cache_flags);
+ }
+
+ CCoinsView root;
+ CCoinsViewCacheTest base{&root};
+ CCoinsViewCacheTest cache{&base};
+};
+
+void CheckAccessCoins(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.SelfTest();
+
+ CAmount result_value;
+ char result_flags;
+ GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
+ BOOST_CHECK_EQUAL(result_value, expected_value);
+ BOOST_CHECK_EQUAL(result_flags, expected_flags);
+}
+
+BOOST_AUTO_TEST_CASE(ccoins_access)
+{
+ /* Check AccessCoin behavior, requesting a coin from a cache view layered on
+ * top of a base view, and checking the resulting entry in the cache after
+ * the 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);
+}
+
+void CheckModifyCoins(CAmount base_value, CAmount cache_value, CAmount modify_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.SelfTest();
+
+ CAmount result_value;
+ char result_flags;
+ GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
+ BOOST_CHECK_EQUAL(result_value, expected_value);
+ BOOST_CHECK_EQUAL(result_flags, expected_flags);
+};
+
+BOOST_AUTO_TEST_CASE(ccoins_modify)
+{
+ /* 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
+ * the resulting entry in the cache after the modification.
+ *
+ * Base Cache Write Result Cache Result
+ * Value 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);
+}
+
+void CheckModifyNewCoinsBase(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));
+ GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
+ } catch (std::logic_error& e) {
+ result_value = FAIL;
+ result_flags = NO_ENTRY;
+ }
+
+ BOOST_CHECK_EQUAL(result_value, expected_value);
+ BOOST_CHECK_EQUAL(result_flags, expected_flags);
+}
+
+// Simple wrapper for CheckModifyNewCoinsBase 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
+// ignores base values.
+template <typename... Args>
+void CheckModifyNewCoins(Args&&... args)
+{
+ for (CAmount base_value : {ABSENT, PRUNED, VALUE1})
+ CheckModifyNewCoinsBase(base_value, std::forward<Args>(args)...);
+}
+
+BOOST_AUTO_TEST_CASE(ccoins_modify_new)
+{
+ /* Check ModifyNewCoin 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.
+ *
+ * Cache Write Result Cache Result Coinbase
+ * 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 );
+}
+
+void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected_value, char parent_flags, char child_flags, char expected_flags)
+{
+ SingleEntryCacheTest test(ABSENT, parent_value, parent_flags);
+
+ CAmount result_value;
+ char result_flags;
+ try {
+ WriteCoinsViewEntry(test.cache, child_value, child_flags);
+ test.cache.SelfTest();
+ GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
+ } catch (std::logic_error& e) {
+ result_value = FAIL;
+ result_flags = NO_ENTRY;
+ }
+
+ BOOST_CHECK_EQUAL(result_value, expected_value);
+ BOOST_CHECK_EQUAL(result_flags, expected_flags);
+}
+
+BOOST_AUTO_TEST_CASE(ccoins_write)
+{
+ /* Check BatchWrite behavior, flushing one entry from a child cache to a
+ * parent cache, and checking the resulting entry in the parent cache
+ * after the write.
+ *
+ * Parent Child Result Parent Child Result
+ * Value Value Value Flags Flags Flags
+ */
+ CheckWriteCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY , NO_ENTRY );
+ CheckWriteCoins(ABSENT, PRUNED, PRUNED, NO_ENTRY , DIRTY , DIRTY );
+ CheckWriteCoins(ABSENT, PRUNED, ABSENT, NO_ENTRY , DIRTY|FRESH, NO_ENTRY );
+ CheckWriteCoins(ABSENT, VALUE2, VALUE2, NO_ENTRY , DIRTY , DIRTY );
+ CheckWriteCoins(ABSENT, VALUE2, VALUE2, NO_ENTRY , DIRTY|FRESH, DIRTY|FRESH);
+ CheckWriteCoins(PRUNED, ABSENT, PRUNED, 0 , NO_ENTRY , 0 );
+ CheckWriteCoins(PRUNED, ABSENT, PRUNED, FRESH , NO_ENTRY , FRESH );
+ CheckWriteCoins(PRUNED, ABSENT, PRUNED, DIRTY , NO_ENTRY , DIRTY );
+ CheckWriteCoins(PRUNED, ABSENT, PRUNED, DIRTY|FRESH, NO_ENTRY , DIRTY|FRESH);
+ CheckWriteCoins(PRUNED, PRUNED, PRUNED, 0 , DIRTY , DIRTY );
+ CheckWriteCoins(PRUNED, PRUNED, PRUNED, 0 , DIRTY|FRESH, DIRTY );
+ CheckWriteCoins(PRUNED, PRUNED, ABSENT, FRESH , DIRTY , NO_ENTRY );
+ CheckWriteCoins(PRUNED, PRUNED, ABSENT, FRESH , DIRTY|FRESH, NO_ENTRY );
+ CheckWriteCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY , DIRTY );
+ CheckWriteCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY|FRESH, DIRTY );
+ CheckWriteCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, DIRTY , NO_ENTRY );
+ CheckWriteCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY );
+ CheckWriteCoins(PRUNED, VALUE2, VALUE2, 0 , DIRTY , DIRTY );
+ CheckWriteCoins(PRUNED, VALUE2, VALUE2, 0 , DIRTY|FRESH, DIRTY );
+ CheckWriteCoins(PRUNED, VALUE2, VALUE2, FRESH , DIRTY , DIRTY|FRESH);
+ CheckWriteCoins(PRUNED, VALUE2, VALUE2, FRESH , DIRTY|FRESH, DIRTY|FRESH);
+ CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY , DIRTY , DIRTY );
+ CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY , DIRTY|FRESH, DIRTY );
+ CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY , DIRTY|FRESH);
+ CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH, DIRTY|FRESH);
+ CheckWriteCoins(VALUE1, ABSENT, VALUE1, 0 , NO_ENTRY , 0 );
+ CheckWriteCoins(VALUE1, ABSENT, VALUE1, FRESH , NO_ENTRY , FRESH );
+ CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY , NO_ENTRY , DIRTY );
+ CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY|FRESH, NO_ENTRY , DIRTY|FRESH);
+ CheckWriteCoins(VALUE1, PRUNED, PRUNED, 0 , DIRTY , DIRTY );
+ CheckWriteCoins(VALUE1, PRUNED, FAIL , 0 , DIRTY|FRESH, NO_ENTRY );
+ CheckWriteCoins(VALUE1, PRUNED, ABSENT, FRESH , DIRTY , NO_ENTRY );
+ CheckWriteCoins(VALUE1, PRUNED, FAIL , FRESH , DIRTY|FRESH, NO_ENTRY );
+ CheckWriteCoins(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY , DIRTY );
+ CheckWriteCoins(VALUE1, PRUNED, FAIL , DIRTY , DIRTY|FRESH, NO_ENTRY );
+ CheckWriteCoins(VALUE1, PRUNED, ABSENT, DIRTY|FRESH, DIRTY , NO_ENTRY );
+ CheckWriteCoins(VALUE1, PRUNED, FAIL , DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY );
+ CheckWriteCoins(VALUE1, VALUE2, VALUE2, 0 , DIRTY , DIRTY );
+ CheckWriteCoins(VALUE1, VALUE2, FAIL , 0 , DIRTY|FRESH, NO_ENTRY );
+ CheckWriteCoins(VALUE1, VALUE2, VALUE2, FRESH , DIRTY , DIRTY|FRESH);
+ CheckWriteCoins(VALUE1, VALUE2, FAIL , FRESH , DIRTY|FRESH, NO_ENTRY );
+ CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY , DIRTY , DIRTY );
+ CheckWriteCoins(VALUE1, VALUE2, FAIL , DIRTY , DIRTY|FRESH, NO_ENTRY );
+ CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY , DIRTY|FRESH);
+ CheckWriteCoins(VALUE1, VALUE2, FAIL , DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY );
+
+ // The checks above omit cases where the child flags are not DIRTY, since
+ // they would be too repetitive (the parent cache is never updated in these
+ // cases). The loop below covers these cases and makes sure the parent cache
+ // is always left unchanged.
+ for (CAmount parent_value : {ABSENT, PRUNED, VALUE1})
+ for (CAmount child_value : {ABSENT, PRUNED, VALUE2})
+ for (char parent_flags : parent_value == ABSENT ? ABSENT_FLAGS : FLAGS)
+ for (char child_flags : child_value == ABSENT ? ABSENT_FLAGS : CLEAN_FLAGS)
+ CheckWriteCoins(parent_value, child_value, parent_value, parent_flags, child_flags, parent_flags);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 58a62ee022..72e562808a 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -1,8 +1,9 @@
-// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Copyright (c) 2014-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 "crypto/aes.h"
+#include "crypto/chacha20.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
@@ -12,6 +13,7 @@
#include "random.h"
#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
+#include "test/test_random.h"
#include <vector>
@@ -133,13 +135,13 @@ 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]);
- if (size != 0)
+ int _size = enc.Encrypt(&sub[0], sub.size(), &subout[0]);
+ if (_size != 0)
{
- subout.resize(size);
+ subout.resize(_size);
std::vector<unsigned char> subdecrypted(subout.size());
- size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]);
- subdecrypted.resize(size);
+ _size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]);
+ subdecrypted.resize(_size);
BOOST_CHECK(decrypted.size() == in.size());
BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub));
}
@@ -174,19 +176,32 @@ 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]);
- if (size != 0)
+ int _size = enc.Encrypt(&sub[0], sub.size(), &subout[0]);
+ if (_size != 0)
{
- subout.resize(size);
+ subout.resize(_size);
std::vector<unsigned char> subdecrypted(subout.size());
- size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]);
- subdecrypted.resize(size);
+ _size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]);
+ subdecrypted.resize(_size);
BOOST_CHECK(decrypted.size() == in.size());
BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub));
}
}
}
+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 +454,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
new file mode 100644
index 0000000000..8cae4e66e8
--- /dev/null
+++ b/src/test/cuckoocache_tests.cpp
@@ -0,0 +1,382 @@
+// Copyright (c) 2012-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 <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
+ *
+ * 1) All tests should have a deterministic result (using insecure rand
+ * 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, 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);
+
+BOOST_AUTO_TEST_SUITE(cuckoocache_tests);
+
+
+/** insecure_GetRandHash fills in a uint256 from insecure_rand
+ */
+void insecure_GetRandHash(uint256& t)
+{
+ uint32_t* ptr = (uint32_t*)t.begin();
+ for (uint8_t j = 0; j < 8; ++j)
+ *(ptr++) = insecure_rand.rand32();
+}
+
+
+
+/* Test that no values not inserted into the cache are read out of it.
+ *
+ * There are no repeats in the first 200000 insecure_GetRandHash calls
+ */
+BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes)
+{
+ insecure_rand = 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);
+ cc.insert(v);
+ }
+ for (int x = 0; x < 100000; ++x) {
+ insecure_GetRandHash(v);
+ BOOST_CHECK(!cc.contains(v, false));
+ }
+};
+
+/** This helper returns the hit rate when megabytes*load worth of entries are
+ * inserted into a megabytes sized cache
+ */
+template <typename Cache>
+double test_cache(size_t megabytes, double load)
+{
+ insecure_rand = FastRandomContext(true);
+ std::vector<uint256> hashes;
+ Cache set{};
+ size_t bytes = megabytes * (1 << 20);
+ set.setup_bytes(bytes);
+ uint32_t n_insert = static_cast<uint32_t>(load * (bytes / sizeof(uint256)));
+ hashes.resize(n_insert);
+ 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();
+ }
+ /** We make a copy of the hashes because future optimizations of the
+ * cuckoocache may overwrite the inserted element, so the test is
+ * "future proofed".
+ */
+ std::vector<uint256> hashes_insert_copy = hashes;
+ /** Do the insert */
+ for (uint256& h : hashes_insert_copy)
+ set.insert(h);
+ /** Count the hits */
+ uint32_t count = 0;
+ for (uint256& h : hashes)
+ count += set.contains(h, false);
+ double hit_rate = ((double)count) / ((double)n_insert);
+ return hit_rate;
+}
+
+/** The normalized hit rate for a given load.
+ *
+ * The semantics are a little confusing, so please see the below
+ * explanation.
+ *
+ * Examples:
+ *
+ * 1) at load 0.5, we expect a perfect hit rate, so we multiply by
+ * 1.0
+ * 2) at load 2.0, we expect to see half the entries, so a perfect hit rate
+ * would be 0.5. Therefore, if we see a hit rate of 0.4, 0.4*2.0 = 0.8 is the
+ * normalized hit rate.
+ *
+ * This is basically the right semantics, but has a bit of a glitch depending on
+ * how you measure around load 1.0 as after load 1.0 your normalized hit rate
+ * becomes effectively perfect, ignoring freshness.
+ */
+double normalize_hit_rate(double hits, double load)
+{
+ return hits * std::max(load, 1.0);
+}
+
+/** Check the hit rate on loads ranging from 0.1 to 2.0 */
+BOOST_AUTO_TEST_CASE(cuckoocache_hit_rate_ok)
+{
+ /** Arbitrarily selected Hit Rate threshold that happens to work for this test
+ * as a lower bound on performance.
+ */
+ double HitRateThresh = 0.98;
+ size_t megabytes = 4;
+ for (double load = 0.1; load < 2; load *= 2) {
+ double hits = test_cache<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes, load);
+ BOOST_CHECK(normalize_hit_rate(hits, load) > HitRateThresh);
+ }
+}
+
+
+/** This helper checks that erased elements are preferentially inserted onto and
+ * that the hit rate of "fresher" keys is reasonable*/
+template <typename Cache>
+void test_cache_erase(size_t megabytes)
+{
+ double load = 1;
+ insecure_rand = FastRandomContext(true);
+ std::vector<uint256> hashes;
+ Cache set{};
+ size_t bytes = megabytes * (1 << 20);
+ set.setup_bytes(bytes);
+ uint32_t n_insert = static_cast<uint32_t>(load * (bytes / sizeof(uint256)));
+ hashes.resize(n_insert);
+ 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();
+ }
+ /** We make a copy of the hashes because future optimizations of the
+ * cuckoocache may overwrite the inserted element, so the test is
+ * "future proofed".
+ */
+ std::vector<uint256> hashes_insert_copy = hashes;
+
+ /** Insert the first half */
+ for (uint32_t i = 0; i < (n_insert / 2); ++i)
+ set.insert(hashes_insert_copy[i]);
+ /** Erase the first quarter */
+ for (uint32_t i = 0; i < (n_insert / 4); ++i)
+ set.contains(hashes[i], true);
+ /** Insert the second half */
+ for (uint32_t i = (n_insert / 2); i < n_insert; ++i)
+ set.insert(hashes_insert_copy[i]);
+
+ /** elements that we marked erased but that are still there */
+ size_t count_erased_but_contained = 0;
+ /** elements that we did not erase but are older */
+ size_t count_stale = 0;
+ /** elements that were most recently inserted */
+ size_t count_fresh = 0;
+
+ for (uint32_t i = 0; i < (n_insert / 4); ++i)
+ count_erased_but_contained += set.contains(hashes[i], false);
+ for (uint32_t i = (n_insert / 4); i < (n_insert / 2); ++i)
+ count_stale += set.contains(hashes[i], false);
+ for (uint32_t i = (n_insert / 2); i < n_insert; ++i)
+ count_fresh += set.contains(hashes[i], false);
+
+ double hit_rate_erased_but_contained = double(count_erased_but_contained) / (double(n_insert) / 4.0);
+ double hit_rate_stale = double(count_stale) / (double(n_insert) / 4.0);
+ double hit_rate_fresh = double(count_fresh) / (double(n_insert) / 2.0);
+
+ // Check that our hit_rate_fresh is perfect
+ BOOST_CHECK_EQUAL(hit_rate_fresh, 1.0);
+ // Check that we have a more than 2x better hit rate on stale elements than
+ // erased elements.
+ BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained);
+}
+
+BOOST_AUTO_TEST_CASE(cuckoocache_erase_ok)
+{
+ 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);
+ std::vector<uint256> hashes;
+ Cache set{};
+ size_t bytes = megabytes * (1 << 20);
+ set.setup_bytes(bytes);
+ uint32_t n_insert = static_cast<uint32_t>(load * (bytes / sizeof(uint256)));
+ hashes.resize(n_insert);
+ 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();
+ }
+ /** We make a copy of the hashes because future optimizations of the
+ * cuckoocache may overwrite the inserted element, so the test is
+ * "future proofed".
+ */
+ std::vector<uint256> hashes_insert_copy = hashes;
+ boost::shared_mutex mtx;
+
+ {
+ /** Grab lock to make sure we release inserts */
+ boost::unique_lock<boost::shared_mutex> l(mtx);
+ /** Insert the first half */
+ for (uint32_t i = 0; i < (n_insert / 2); ++i)
+ set.insert(hashes_insert_copy[i]);
+ }
+
+ /** Spin up 3 threads to run contains with erase.
+ */
+ std::vector<std::thread> threads;
+ /** Erase the first quarter */
+ for (uint32_t x = 0; x < 3; ++x)
+ /** Each thread is emplaced with x copy-by-value
+ */
+ threads.emplace_back([&, x] {
+ boost::shared_lock<boost::shared_mutex> l(mtx);
+ size_t ntodo = (n_insert/4)/3;
+ size_t start = ntodo*x;
+ size_t end = ntodo*(x+1);
+ for (uint32_t i = start; i < end; ++i)
+ set.contains(hashes[i], true);
+ });
+
+ /** Wait for all threads to finish
+ */
+ for (std::thread& t : threads)
+ t.join();
+ /** Grab lock to make sure we observe erases */
+ boost::unique_lock<boost::shared_mutex> l(mtx);
+ /** Insert the second half */
+ for (uint32_t i = (n_insert / 2); i < n_insert; ++i)
+ set.insert(hashes_insert_copy[i]);
+
+ /** elements that we marked erased but that are still there */
+ size_t count_erased_but_contained = 0;
+ /** elements that we did not erase but are older */
+ size_t count_stale = 0;
+ /** elements that were most recently inserted */
+ size_t count_fresh = 0;
+
+ for (uint32_t i = 0; i < (n_insert / 4); ++i)
+ count_erased_but_contained += set.contains(hashes[i], false);
+ for (uint32_t i = (n_insert / 4); i < (n_insert / 2); ++i)
+ count_stale += set.contains(hashes[i], false);
+ for (uint32_t i = (n_insert / 2); i < n_insert; ++i)
+ count_fresh += set.contains(hashes[i], false);
+
+ double hit_rate_erased_but_contained = double(count_erased_but_contained) / (double(n_insert) / 4.0);
+ double hit_rate_stale = double(count_stale) / (double(n_insert) / 4.0);
+ double hit_rate_fresh = double(count_fresh) / (double(n_insert) / 2.0);
+
+ // Check that our hit_rate_fresh is perfect
+ BOOST_CHECK_EQUAL(hit_rate_fresh, 1.0);
+ // Check that we have a more than 2x better hit rate on stale elements than
+ // erased elements.
+ BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained);
+}
+BOOST_AUTO_TEST_CASE(cuckoocache_erase_parallel_ok)
+{
+ size_t megabytes = 4;
+ test_cache_erase_parallel<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes);
+}
+
+
+template <typename Cache>
+void test_cache_generations()
+{
+ // This test checks that for a simulation of network activity, the fresh hit
+ // rate is never below 99%, and the number of times that it is worse than
+ // 99.9% are less than 1% of the time.
+ double min_hit_rate = 0.99;
+ double tight_hit_rate = 0.999;
+ double max_rate_less_than_tight_hit_rate = 0.01;
+ // A cache that meets this specification is therefore shown to have a hit
+ // rate of at least tight_hit_rate * (1 - max_rate_less_than_tight_hit_rate) +
+ // min_hit_rate*max_rate_less_than_tight_hit_rate = 0.999*99%+0.99*1% == 99.89%
+ // hit rate with low variance.
+
+ // We use deterministic values, but this test has also passed on many
+ // 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);
+
+ // 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
+ // and the middle n/2 are not stored. This models a network which uses half
+ // the signatures of recently (since the last block) added transactions
+ // immediately and never uses the other half.
+ struct block_activity {
+ std::vector<uint256> reads;
+ block_activity(uint32_t n_insert, Cache& c) : reads()
+ {
+ std::vector<uint256> inserts;
+ inserts.resize(n_insert);
+ reads.reserve(n_insert / 2);
+ 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();
+ }
+ for (uint32_t i = 0; i < n_insert / 4; ++i)
+ reads.push_back(inserts[i]);
+ for (uint32_t i = n_insert - (n_insert / 4); i < n_insert; ++i)
+ reads.push_back(inserts[i]);
+ for (auto h : inserts)
+ c.insert(h);
+ }
+ };
+
+ 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 = 4;
+ const size_t bytes = megabytes * (1 << 20);
+ const uint32_t n_insert = static_cast<uint32_t>(load * (bytes / sizeof(uint256)));
+
+ std::vector<block_activity> hashes;
+ Cache set{};
+ set.setup_bytes(bytes);
+ hashes.reserve(n_insert / BLOCK_SIZE);
+ std::deque<block_activity> last_few;
+ uint32_t out_of_tight_tolerance = 0;
+ uint32_t total = n_insert / BLOCK_SIZE;
+ // we use the deque last_few to model a sliding window of blocks. at each
+ // step, each of the last WINDOW_SIZE block_activities checks the cache for
+ // POP_AMOUNT of the hashes that they inserted, and marks these erased.
+ for (uint32_t i = 0; i < total; ++i) {
+ if (last_few.size() == WINDOW_SIZE)
+ last_few.pop_front();
+ last_few.emplace_back(BLOCK_SIZE, set);
+ uint32_t count = 0;
+ for (auto& act : last_few)
+ for (uint32_t k = 0; k < POP_AMOUNT; ++k) {
+ count += set.contains(act.reads.back(), true);
+ act.reads.pop_back();
+ }
+ // We use last_few.size() rather than WINDOW_SIZE for the correct
+ // behavior on the first WINDOW_SIZE iterations where the deque is not
+ // full yet.
+ double hit = (double(count)) / (last_few.size() * POP_AMOUNT);
+ // 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 implicitly, greater than min_hit_rate)
+ out_of_tight_tolerance += hit < tight_hit_rate;
+ }
+ // Check that being out of tolerance happens less than
+ // max_rate_less_than_tight_hit_rate of the time
+ BOOST_CHECK(double(out_of_tight_tolerance) / double(total) < max_rate_less_than_tight_hit_rate);
+}
+BOOST_AUTO_TEST_CASE(cuckoocache_generations)
+{
+ test_cache_generations<CuckooCache::cache<uint256, SignatureCacheHasher>>();
+}
+
+BOOST_AUTO_TEST_SUITE_END();
diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json
deleted file mode 100644
index 5cb383de85..0000000000
--- a/src/test/data/bitcoin-util-test.json
+++ /dev/null
@@ -1,103 +0,0 @@
-[
- { "exec": "././bitcoin-tx",
- "args": ["-create"],
- "output_cmp": "blanktx.hex"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-"],
- "input": "blanktx.hex",
- "output_cmp": "blanktx.hex"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-", "delin=1"],
- "input": "tx394b54bb.hex",
- "output_cmp": "tt-delin1-out.hex"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-", "delin=31"],
- "input": "tx394b54bb.hex",
- "return_code": 1
- },
- { "exec": "./bitcoin-tx",
- "args": ["-", "delout=1"],
- "input": "tx394b54bb.hex",
- "output_cmp": "tt-delout1-out.hex"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-", "delout=2"],
- "input": "tx394b54bb.hex",
- "return_code": 1
- },
- { "exec": "./bitcoin-tx",
- "args": ["-", "locktime=317000"],
- "input": "tx394b54bb.hex",
- "output_cmp": "tt-locktime317000-out.hex"
- },
- { "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"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-create", "outscript=0:"],
- "output_cmp": "txcreate2.hex"
- },
- { "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": "txcreatesign.hex"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "outdata=4:badhexdata"],
- "return_code": 1
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "outdata=badhexdata"],
- "return_code": 1
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
- "outdata=4:54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"],
- "output_cmp": "txcreatedata1.hex"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
- "outdata=54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"],
- "output_cmp": "txcreatedata2.hex"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:4294967293",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"],
- "output_cmp": "txcreatedata_seq0.hex"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:1"],
- "output_cmp": "txcreatedata_seq1.hex"
- }
-]
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index fcd5457386..e35a7ce569 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -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"],
@@ -1492,6 +1492,27 @@
"BIP66 example 4, with DERSIG"
],
[
+ "0x09 0x300602010102010101",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
+ "DERSIG",
+ "OK",
+ "BIP66 example 4, with DERSIG, non-null DER-compliant signature"
+],
+[
+ "0",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
+ "DERSIG,NULLFAIL",
+ "OK",
+ "BIP66 example 4, with DERSIG and NULLFAIL"
+],
+[
+ "0x09 0x300602010102010101",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
+ "DERSIG,NULLFAIL",
+ "NULLFAIL",
+ "BIP66 example 4, with DERSIG and NULLFAIL, non-null DER-compliant signature"
+],
+[
"1",
"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
"",
@@ -1834,6 +1855,8 @@
"OK",
"P2SH with CLEANSTACK"
],
+
+["Testing with uncompressed keys in witness v0 without WITNESS_PUBKEYTYPE"],
[
[
"304402200d461c140cfdfcf36b94961db57ae8c18d1cb80e9d95a9e47ac22470c1bf125502201c8dc1cbfef6a3ef90acbbb992ca22fe9466ee6f9d4898eda277a7ac3ab4b25101",
@@ -2118,12 +2141,469 @@
"P2PK with witness"
],
-["CHECKSEQUENCEVERIFY tests"],
+["Testing with compressed keys in witness v0 with WITNESS_PUBKEYTYPE"],
+[
+ [
+ "304402204256146fcf8e73b0fd817ffa2a4e408ff0418ff987dd08a4f485b62546f6c43c02203f3c8c3e2febc051e1222867f5f9d0eaf039d6792911c10940aa3cc74123378e01",
+ "210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "Basic P2WSH with compressed key"
+],
+[
+ [
+ "304402204edf27486f11432466b744df533e1acac727e0c83e5f912eb289a3df5bf8035f022075809fdd876ede40ad21667eba8b7e96394938f9c9c50f11b6a1280cce2cea8601",
+ "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ 0.00000001
+ ],
+ "",
+ "0 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "Basic P2WPKH with compressed key"
+],
+[
+ [
+ "304402203a549090cc46bce1e5e95c4922ea2c12747988e0207b04c42f81cdbe87bb1539022050f57a245b875fd5119c419aaf050bcdf41384f0765f04b809e5bced1fe7093d01",
+ "210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ 0.00000001
+ ],
+ "0x22 0x00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
+ "HASH160 0x14 0xe4300531190587e3880d4c3004f5355d88ff928d EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "Basic P2SH(P2WSH) with compressed key"
+],
+[
+ [
+ "304402201bc0d53046827f4a35a3166e33e3b3366c4085540dc383b95d21ed2ab11e368a0220333e78c6231214f5f8e59621e15d7eeab0d4e4d0796437e00bfbd2680c5f9c1701",
+ "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ 0.00000001
+ ],
+ "0x16 0x0014751e76e8199196d454941c45d1b3a323f1433bd6",
+ "HASH160 0x14 0xbcfeb728b584253d5f3f70bcb780e9ef218a68f4 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "Basic P2SH(P2WPKH) with compressed key"
+],
+
+["Testing with uncompressed keys in witness v0 with WITNESS_PUBKEYTYPE"],
+[
+ [
+ "304402200d461c140cfdfcf36b94961db57ae8c18d1cb80e9d95a9e47ac22470c1bf125502201c8dc1cbfef6a3ef90acbbb992ca22fe9466ee6f9d4898eda277a7ac3ab4b25101",
+ "410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "Basic P2WSH"
+],
+[
+ [
+ "304402201e7216e5ccb3b61d46946ec6cc7e8c4e0117d13ac2fd4b152197e4805191c74202203e9903e33e84d9ee1dd13fb057afb7ccfb47006c23f6a067185efbc9dd780fc501",
+ "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
+ 0.00000001
+ ],
+ "",
+ "0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "Basic P2WPKH"
+],
+[
+ [
+ "3044022066e02c19a513049d49349cf5311a1b012b7c4fae023795a18ab1d91c23496c22022025e216342c8e07ce8ef51e8daee88f84306a9de66236cab230bb63067ded1ad301",
+ "410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",
+ 0.00000001
+ ],
+ "0x22 0x0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64",
+ "HASH160 0x14 0xf386c2ba255cc56d20cfa6ea8b062f8b59945518 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "Basic P2SH(P2WSH)"
+],
+[
+ [
+ "304402200929d11561cd958460371200f82e9cae64c727a495715a31828e27a7ad57b36d0220361732ced04a6f97351ecca21a56d0b8cd4932c1da1f8f569a2b68e5e48aed7801",
+ "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
+ 0.00000001
+ ],
+ "0x16 0x001491b24bf9f5288532960ac687abb035127b1d28a5",
+ "HASH160 0x14 0x17743beb429c55c942d2ec703b98c4d57c2df5c6 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "Basic P2SH(P2WPKH)"
+],
+
+["Testing P2WSH multisig with compressed keys"],
+[
+ [
+ "",
+ "304402207eb8a59b5c65fc3f6aeef77066556ed5c541948a53a3ba7f7c375b8eed76ee7502201e036a7a9a98ff919ff94dc905d67a1ec006f79ef7cff0708485c8bb79dce38e01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x06c24420938f0fa3c1cb2707d867154220dca365cdbfa0dd2a83854730221460",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2WSH CHECKMULTISIG with compressed keys"
+],
+[
+ [
+ "",
+ "3044022033706aed33b8155d5486df3b9bca8cdd3bd4bdb5436dce46d72cdaba51d22b4002203626e94fe53a178af46624f17315c6931f20a30b103f5e044e1eda0c3fe185c601",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x002006c24420938f0fa3c1cb2707d867154220dca365cdbfa0dd2a83854730221460",
+ "HASH160 0x14 0x26282aad7c29369d15fed062a778b6100d31a340 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG with compressed keys"
+],
+[
+ [
+ "",
+ "304402204048b7371ab1c544362efb89af0c80154747d665aa4fcfb2edfd2d161e57b42e02207e043748e96637080ffc3acbd4dcc6fee1e58d30f6d1269535f32188e5ddae7301",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x06c24420938f0fa3c1cb2707d867154220dca365cdbfa0dd2a83854730221460",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2WSH CHECKMULTISIG with compressed keys"
+],
+[
+ [
+ "",
+ "3044022073902ef0b8a554c36c44cc03c1b64df96ce2914ebcf946f5bb36078fd5245cdf02205b148f1ba127065fb8c83a5a9576f2dcd111739788ed4bb3ee08b2bd3860c91c01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x002006c24420938f0fa3c1cb2707d867154220dca365cdbfa0dd2a83854730221460",
+ "HASH160 0x14 0x26282aad7c29369d15fed062a778b6100d31a340 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG with compressed keys"
+],
+
+["Testing P2WSH multisig with compressed and uncompressed keys (first key being the key closer to the top of stack)"],
+[
+ [
+ "",
+ "304402202d092ededd1f060609dbf8cb76950634ff42b3e62cf4adb69ab92397b07d742302204ff886f8d0817491a96d1daccdcc820f6feb122ee6230143303100db37dfa79f01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x08a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "P2SH,WITNESS",
+ "OK",
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "304402202dd7e91243f2235481ffb626c3b7baf2c859ae3a5a77fb750ef97b99a8125dc002204960de3d3c3ab9496e218ec57e5240e0e10a6f9546316fe240c216d45116d29301",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "0x22 0x002008a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "HASH160 0x14 0x6f5ecd4b83b77f3c438f5214eff96454934fc5d1 EQUAL",
+ "P2SH,WITNESS",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG first key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "304402202d092ededd1f060609dbf8cb76950634ff42b3e62cf4adb69ab92397b07d742302204ff886f8d0817491a96d1daccdcc820f6feb122ee6230143303100db37dfa79f01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x08a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "304402202dd7e91243f2235481ffb626c3b7baf2c859ae3a5a77fb750ef97b99a8125dc002204960de3d3c3ab9496e218ec57e5240e0e10a6f9546316fe240c216d45116d29301",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "0x22 0x002008a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "HASH160 0x14 0x6f5ecd4b83b77f3c438f5214eff96454934fc5d1 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "304402201e9e6f7deef5b2f21d8223c5189b7d5e82d237c10e97165dd08f547c4e5ce6ed02206796372eb1cc6acb52e13ee2d7f45807780bf96b132cb6697f69434be74b1af901",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x08a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "P2SH,WITNESS",
+ "OK",
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "3044022045e667f3f0f3147b95597a24babe9afecea1f649fd23637dfa7ed7e9f3ac18440220295748e81005231135289fe3a88338dabba55afa1bdb4478691337009d82b68d01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "0x22 0x002008a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "HASH160 0x14 0x6f5ecd4b83b77f3c438f5214eff96454934fc5d1 EQUAL",
+ "P2SH,WITNESS",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "304402201e9e6f7deef5b2f21d8223c5189b7d5e82d237c10e97165dd08f547c4e5ce6ed02206796372eb1cc6acb52e13ee2d7f45807780bf96b132cb6697f69434be74b1af901",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x08a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "3044022045e667f3f0f3147b95597a24babe9afecea1f649fd23637dfa7ed7e9f3ac18440220295748e81005231135289fe3a88338dabba55afa1bdb4478691337009d82b68d01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "0x22 0x002008a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "HASH160 0x14 0x6f5ecd4b83b77f3c438f5214eff96454934fc5d1 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "3044022046f5367a261fd8f8d7de6eb390491344f8ec2501638fb9a1095a0599a21d3f4c02205c1b3b51d20091c5f1020841bbca87b44ebe25405c64e4acf758f2eae8665f8401",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "P2SH,WITNESS",
+ "OK",
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "3044022053e210e4fb1881e6092fd75c3efc5163105599e246ded661c0ee2b5682cc2d6c02203a26b7ada8682a095b84c6d1b881637000b47d761fc837c4cee33555296d63f101",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x0020230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "HASH160 0x14 0x3478e7019ce61a68148f87549579b704cbe4c393 EQUAL",
+ "P2SH,WITNESS",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG second key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "3044022046f5367a261fd8f8d7de6eb390491344f8ec2501638fb9a1095a0599a21d3f4c02205c1b3b51d20091c5f1020841bbca87b44ebe25405c64e4acf758f2eae8665f8401",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used"
+],
+[
+ [
+ "",
+ "3044022053e210e4fb1881e6092fd75c3efc5163105599e246ded661c0ee2b5682cc2d6c02203a26b7ada8682a095b84c6d1b881637000b47d761fc837c4cee33555296d63f101",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x0020230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "HASH160 0x14 0x3478e7019ce61a68148f87549579b704cbe4c393 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used"
+],
+[
+ [
+ "",
+ "304402206c6d9f5daf85b54af2a93ec38b15ab27f205dbf5c735365ff12451e43613d1f40220736a44be63423ed5ebf53491618b7cc3d8a5093861908da853739c73717938b701",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "P2SH,WITNESS",
+ "OK",
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "30440220687871bc6144012d75baf585bb26ce13997f7d8c626f4d8825b069c3b2d064470220108936fe1c57327764782253e99090b09c203ec400ed35ce9e026ce2ecf842a001",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x0020230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "HASH160 0x14 0x3478e7019ce61a68148f87549579b704cbe4c393 EQUAL",
+ "P2SH,WITNESS",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "304402206c6d9f5daf85b54af2a93ec38b15ab27f205dbf5c735365ff12451e43613d1f40220736a44be63423ed5ebf53491618b7cc3d8a5093861908da853739c73717938b701",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "30440220687871bc6144012d75baf585bb26ce13997f7d8c626f4d8825b069c3b2d064470220108936fe1c57327764782253e99090b09c203ec400ed35ce9e026ce2ecf842a001",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x0020230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "HASH160 0x14 0x3478e7019ce61a68148f87549579b704cbe4c393 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key"
+],
+
+["CHECKSEQUENCEVERIFY tests"],
["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a 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"],
["4294967296", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME",
"CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"],
+
+["MINIMALIF tests"],
+["MINIMALIF is not applied to non-segwit scripts"],
+["1", "IF 1 ENDIF", "P2SH,WITNESS,MINIMALIF", "OK"],
+["2", "IF 1 ENDIF", "P2SH,WITNESS,MINIMALIF", "OK"],
+["0x02 0x0100", "IF 1 ENDIF", "P2SH,WITNESS,MINIMALIF", "OK"],
+["0", "IF 1 ENDIF", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+["0x01 0x00", "IF 1 ENDIF", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+["1", "NOTIF 1 ENDIF", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+["2", "NOTIF 1 ENDIF", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+["0x02 0x0100", "NOTIF 1 ENDIF", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+["0", "NOTIF 1 ENDIF", "P2SH,WITNESS,MINIMALIF", "OK"],
+["0x01 0x00", "NOTIF 1 ENDIF", "P2SH,WITNESS,MINIMALIF", "OK"],
+["Normal P2SH IF 1 ENDIF"],
+["1 0x03 0x635168", "HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL", "P2SH,WITNESS,MINIMALIF", "OK"],
+["2 0x03 0x635168", "HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL", "P2SH,WITNESS,MINIMALIF", "OK"],
+["0x02 0x0100 0x03 0x635168", "HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL", "P2SH,WITNESS,MINIMALIF", "OK"],
+["0 0x03 0x635168", "HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+["0x01 0x00 0x03 0x635168", "HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+["0x03 0x635168", "HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL", "P2SH,WITNESS,MINIMALIF", "UNBALANCED_CONDITIONAL"],
+["Normal P2SH NOTIF 1 ENDIF"],
+["1 0x03 0x645168", "HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+["2 0x03 0x645168", "HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+["0x02 0x0100 0x03 0x645168", "HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+["0 0x03 0x645168", "HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL", "P2SH,WITNESS,MINIMALIF", "OK"],
+["0x01 0x00 0x03 0x645168", "HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL", "P2SH,WITNESS,MINIMALIF", "OK"],
+["0x03 0x645168", "HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL", "P2SH,WITNESS,MINIMALIF", "UNBALANCED_CONDITIONAL"],
+["P2WSH IF 1 ENDIF"],
+[["01", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "OK"],
+[["02", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "OK"],
+[["0100", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "OK"],
+[["", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "EVAL_FALSE"],
+[["00", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "EVAL_FALSE"],
+[["01", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "OK"],
+[["02", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["0100", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+[["00", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "UNBALANCED_CONDITIONAL"],
+[["635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "UNBALANCED_CONDITIONAL"],
+["P2WSH NOTIF 1 ENDIF"],
+[["01", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "EVAL_FALSE"],
+[["02", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "EVAL_FALSE"],
+[["0100", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "EVAL_FALSE"],
+[["", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "OK"],
+[["00", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "OK"],
+[["01", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+[["02", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["0100", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "OK"],
+[["00", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "UNBALANCED_CONDITIONAL"],
+[["645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "UNBALANCED_CONDITIONAL"],
+
+
+
+["P2SH-P2WSH IF 1 ENDIF"],
+[["01", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "OK"],
+[["02", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "OK"],
+[["0100", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "OK"],
+[["", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "EVAL_FALSE"],
+[["00", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "EVAL_FALSE"],
+[["01", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "OK"],
+[["02", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["0100", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+[["00", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "UNBALANCED_CONDITIONAL"],
+[["635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "UNBALANCED_CONDITIONAL"],
+["P2SH-P2WSH NOTIF 1 ENDIF"],
+[["01", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "EVAL_FALSE"],
+[["02", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "EVAL_FALSE"],
+[["0100", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "EVAL_FALSE"],
+[["", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "OK"],
+[["00", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "OK"],
+[["01", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"],
+[["02", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["0100", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "OK"],
+[["00", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"],
+[["645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "UNBALANCED_CONDITIONAL"],
+[["645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "UNBALANCED_CONDITIONAL"],
+
+["NULLFAIL should cover all signatures and signatures only"],
+["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66 and NULLFAIL-compliant"],
+["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "OK", "BIP66 and NULLFAIL-compliant"],
+["1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "OK", "BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant"],
+["1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL,NULLDUMMY", "SIG_NULLDUMMY", "BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant"],
+["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66-compliant but not NULLFAIL-compliant"],
+["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "NULLFAIL", "BIP66-compliant but not NULLFAIL-compliant"],
+["0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG", "OK", "BIP66-compliant but not NULLFAIL-compliant"],
+["0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT", "DERSIG,NULLFAIL", "NULLFAIL", "BIP66-compliant but not NULLFAIL-compliant"],
+
["The End"]
]
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index f8baee0577..2235bd0ae7 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"],
@@ -314,5 +314,31 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x60 0x21 0xff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbff", 1000]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e803000000000000015100000000", "P2SH,WITNESS,DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"],
+["FindAndDelete tests"],
+["This is a test of FindAndDelete. The first tx is a spend of normal scriptPubKey and the second tx is a spend of bare P2WSH."],
+["The redeemScript/witnessScript is CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01>."],
+["The signature is <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> <pubkey>,"],
+["where the pubkey is obtained through key recovery with sig and the wrong sighash."],
+["This is to show that FindAndDelete is applied only to non-segwit scripts"],
+["To show that the tests are 'correctly wrong', they should pass by modifying OP_CHECKSIG under interpreter.cpp"],
+["by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE)"],
+["Non-segwit: wrong sighash (without FindAndDelete) = 1ba1fe3bc90c5d1265460e684ce6774e324f0fabdf67619eda729e64e8b6bc08"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7000, "HASH160 0x14 0x0c746489e2d83cdbb5b90b432773342ba809c134 EQUAL", 200000]],
+"010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012103b12a1ec8428fc74166926318c15e17408fea82dbb157575e16a8c365f546248f4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: wrong sighash (with FindAndDelete) = 71c9cd9b2869b9c70b01b1f0360c148f42dee72297db312638df136f43311f23"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7500, "0x00 0x20 0x9e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19", 200000]],
+"0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9d7ed6e161f0e255c10bbfcca0128a9e2035c2c8da58899c54d22d3a31afdef4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", "P2SH,WITNESS"],
+["This is multisig version of the FindAndDelete tests"],
+["Script is 2 CHECKMULTISIGVERIFY <sig1> <sig2> DROP"],
+["52af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175"],
+["Signature is 0 <sig1> <sig2> 2 <key1> <key2>"],
+["Should pass by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE) under OP_CHECKMULTISIG"],
+["Non-segwit: wrong sighash (without FindAndDelete) = 4bc6a53e8e16ef508c19e38bba08831daba85228b0211f323d4cb0999cf2a5e8"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7000, "HASH160 0x14 0x5748407f5ca5cdca53ba30b79040260770c9ee1b EQUAL", 200000]],
+"01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596015221023fd5dd42b44769c5653cbc5947ff30ab8871f240ad0c0e7432aefe84b5b4ff3421039d52178dbde360b83f19cf348deb04fa8360e1bf5634577be8e50fafc2b0e4ef4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: wrong sighash (with FindAndDelete) = 17c50ec2181ecdfdc85ca081174b248199ba81fff730794d4f69b8ec031f2dce"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7500, "0x00 0x20 0x9b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52", 200000]],
+"010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601010221023cb6055f4b57a1580c5a753e19610cafaedf7e0ff377731c77837fd666eae1712102c1b1db303ac232ffa8e5e7cc2cf5f96c6e40d3e6914061204c0541cb2043a0969552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", "P2SH,WITNESS"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 1ea70135b4..d70fa54333 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"],
@@ -53,7 +53,7 @@
["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"],
["It results in signing the constant 1, instead of something generated based on the transaction,"],
["when the input doing the signing has an index greater than the maximum output index"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"], ["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"]],
"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"],
["An invalid P2SH Transaction"],
@@ -334,9 +334,9 @@
"0100000000010100010000000000000000000000000000000000000000000000000000000000000000000023220020ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100aa5d8aa40a90f23ce2c3d11bc845ca4a12acd99cbea37de6b9f6d86edebba8cb022022dedc2aa0a255f74d04c0b76ece2d7c691f9dd11a64a8ac49f62a99c3a05f9d01232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac00000000", "P2SH,WITNESS"],
["Witness with SigHash Single|AnyoneCanPay"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2000],
-["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
+["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
["0000000000000000000000000000000000000000000000000000000000000100", 3, "0x51", 4100]],
"0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000", "P2SH,WITNESS"],
@@ -359,9 +359,9 @@
"0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"],
["Witness with SigHash None|AnyoneCanPay"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
+["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2000],
-["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
["0000000000000000000000000000000000000000000000000000000000000100", 3, "0x51", 4100]],
"0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff04b60300000000000001519e070000000000000151860b00000000000001009600000000000000015100000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"],
@@ -390,9 +390,9 @@
"01000000000103000100000000000000000000000000000000000000000000000000000000000000000000000200000000010000000000000000000000000000000000000000000000000000000000000100000000ffffffff000100000000000000000000000000000000000000000000000000000000000002000000000200000003e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"],
["Witness with SigHash All|AnyoneCanPay"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
+["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x51", 1100],
["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2000],
-["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3100],
["0000000000000000000000000000000000000000000000000000000000000100", 3, "0x51", 4100]],
"0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "P2SH,WITNESS"],
@@ -458,8 +458,8 @@
"0100000000010200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff02e8030000000000000151e90300000000000001510247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "P2SH,WITNESS"],
["Witness Single|AnyoneCanPay does not hash input's position (permutation)"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1000],
-["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1001]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 1, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1001],
+["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1000]],
"0100000000010200010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff02e9030000000000000151e80300000000000001510248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "P2SH,WITNESS"],
["Non witness Single|AnyoneCanPay hash input's position"],
@@ -478,7 +478,7 @@
["1b2a9a426ba603ba357ce7773cb5805cb9c7c2b386d100d1fc9263513188e680", 0, "0x00 0x20 0xd9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537", 16777215]],
"01000000000102e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000", "P2SH,WITNESS"],
-["BIP143 example: Same as the previous example with input-output paris swapped"],
+["BIP143 example: Same as the previous example with input-output pairs swapped"],
[[["1b2a9a426ba603ba357ce7773cb5805cb9c7c2b386d100d1fc9263513188e680", 0, "0x00 0x20 0xd9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537", 16777215],
["01c0cf7fba650638e55eb91261b183251fbb466f90dff17f10086817c542b5e9", 0, "0x00 0x20 0xba468eea561b26301e4cf69fa34bde4ad60c81e70f059f045ca9a79931004a4d", 16777215]],
"0100000000010280e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffffe9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff0280969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac80969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000", "P2SH,WITNESS"],
@@ -487,5 +487,28 @@
[[["6eb98797a21c6c10aa74edf29d618be109f48a8e94c694f3701e08ca69186436", 1, "HASH160 0x14 0x9993a429037b5d912407a71c252019287b8d27a5 EQUAL", 987654321]],
"0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000", "P2SH,WITNESS"],
+["FindAndDelete tests"],
+["This is a test of FindAndDelete. The first tx is a spend of normal P2SH and the second tx is a spend of bare P2WSH."],
+["The redeemScript/witnessScript is CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01>."],
+["The signature is <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> <pubkey>,"],
+["where the pubkey is obtained through key recovery with sig and correct sighash."],
+["This is to show that FindAndDelete is applied only to non-segwit scripts"],
+["Non-segwit: correct sighash (with FindAndDelete) = 1ba1fe3bc90c5d1265460e684ce6774e324f0fabdf67619eda729e64e8b6bc08"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7000, "HASH160 0x14 0x0c746489e2d83cdbb5b90b432773342ba809c134 EQUAL", 200000]],
+"010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0121037a3fb04bcdb09eba90f69961ba1692a3528e45e67c85b200df820212d7594d334aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: correct sighash (without FindAndDelete) = 71c9cd9b2869b9c70b01b1f0360c148f42dee72297db312638df136f43311f23"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7500, "0x00 0x20 0x9e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19", 200000]],
+"0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", "P2SH,WITNESS"],
+["This is multisig version of the FindAndDelete tests"],
+["Script is 2 CHECKMULTISIGVERIFY <sig1> <sig2> DROP"],
+["52af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175"],
+["Signature is 0 <sig1> <sig2> 2 <key1> <key2>"],
+["Non-segwit: correct sighash (with FindAndDelete) = 1d50f00ba4db2917b903b0ec5002e017343bb38876398c9510570f5dce099295"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7000, "HASH160 0x14 0x5748407f5ca5cdca53ba30b79040260770c9ee1b EQUAL", 200000]],
+"01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601522102cd74a2809ffeeed0092bc124fd79836706e41f048db3f6ae9df8708cefb83a1c2102e615999372426e46fd107b76eaf007156a507584aa2cc21de9eee3bdbd26d36c4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: correct sighash (without FindAndDelete) = c1628a1e7c67f14ca0c27c06e4fdeec2e6d1a73c7a91d7c046ff83e835aebb72"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7500, "0x00 0x20 0x9b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52", 200000]],
+"010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960101022102966f109c54e85d3aee8321301136cedeb9fc710fdef58a9de8a73942f8e567c021034ffc99dd9a79dd3cb31e2ab3e0b09e0e67db41ac068c625cd1f491576016c84e9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", "P2SH,WITNESS"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/data/txcreate2.hex b/src/test/data/txcreate2.hex
deleted file mode 100644
index 5243c2d02e..0000000000
--- a/src/test/data/txcreate2.hex
+++ /dev/null
@@ -1 +0,0 @@
-01000000000100000000000000000000000000
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index a0bdcf4afb..c9d9849ada 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -10,13 +10,9 @@
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/assert.hpp>
#include <boost/test/unit_test.hpp>
-
-using namespace std;
-using namespace boost::assign; // bring 'operator+=()' into scope
-using namespace boost::filesystem;
-
+
// Test if a string consists entirely of null characters
-bool is_null_key(const vector<unsigned char>& key) {
+bool is_null_key(const std::vector<unsigned char>& key) {
bool isnull = true;
for (unsigned int i = 0; i < key.size(); i++)
@@ -32,7 +28,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
// Perform tests both obfuscated and non-obfuscated.
for (int i = 0; i < 2; i++) {
bool obfuscate = (bool)i;
- path ph = temp_directory_path() / unique_path();
+ fs::path ph = fs::temp_directory_path() / fs::unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'k';
uint256 in = GetRandHash();
@@ -53,7 +49,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
// Perform tests both obfuscated and non-obfuscated.
for (int i = 0; i < 2; i++) {
bool obfuscate = (bool)i;
- path ph = temp_directory_path() / unique_path();
+ fs::path ph = fs::temp_directory_path() / fs::unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'i';
@@ -80,7 +76,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);
}
}
@@ -90,7 +86,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
// Perform tests both obfuscated and non-obfuscated.
for (int i = 0; i < 2; i++) {
bool obfuscate = (bool)i;
- path ph = temp_directory_path() / unique_path();
+ 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
@@ -101,7 +97,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
uint256 in2 = GetRandHash();
BOOST_CHECK(dbw.Write(key2, in2));
- boost::scoped_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);
@@ -129,8 +125,8 @@ 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 path between two wrappers
- path ph = temp_directory_path() / 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.
@@ -145,6 +141,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);
@@ -170,8 +167,8 @@ 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 path between two wrappers
- path ph = temp_directory_path() / 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.
@@ -186,6 +183,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);
@@ -206,7 +204,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_AUTO_TEST_CASE(iterator_ordering)
{
- path ph = temp_directory_path() / 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;
@@ -214,7 +212,7 @@ BOOST_AUTO_TEST_CASE(iterator_ordering)
BOOST_CHECK(dbw.Write(key, value));
}
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
for (int c=0; c<2; ++c) {
int seek_start;
if (c == 0)
@@ -241,11 +239,11 @@ BOOST_AUTO_TEST_CASE(iterator_ordering)
struct StringContentsSerializer {
// Used to make two serialized objects the same while letting them have a different lengths
// This is a terrible idea
- string str;
+ std::string str;
StringContentsSerializer() {}
- StringContentsSerializer(const string& inp) : str(inp) {}
+ StringContentsSerializer(const std::string& inp) : str(inp) {}
- StringContentsSerializer& operator+=(const string& s) {
+ StringContentsSerializer& operator+=(const std::string& s) {
str += s;
return *this;
}
@@ -254,7 +252,7 @@ struct StringContentsSerializer {
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
if (ser_action.ForRead()) {
str.clear();
char c = 0;
@@ -277,11 +275,11 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
{
char buf[10];
- path ph = temp_directory_path() / 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;
@@ -290,20 +288,20 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
}
}
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ 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);
+ 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);
- string exp_key(buf);
+ snprintf(buf, sizeof(buf), "%d", x);
+ std::string exp_key(buf);
for (int z = 0; z < y; z++)
exp_key += exp_key;
StringContentsSerializer key;
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index 82d61209b5..d8de765db1 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2013-2015 The Bitcoin Core developers
+// Copyright (c) 2013-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.
@@ -10,8 +10,6 @@
#include <boost/test/unit_test.hpp>
-using namespace std;
-
BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(murmurhash3)
@@ -122,6 +120,14 @@ BOOST_AUTO_TEST_CASE(siphash)
hasher3.Write(uint64_t(x)|(uint64_t(x+1)<<8)|(uint64_t(x+2)<<16)|(uint64_t(x+3)<<24)|
(uint64_t(x+4)<<32)|(uint64_t(x+5)<<40)|(uint64_t(x+6)<<48)|(uint64_t(x+7)<<56));
}
+
+ CHashWriter ss(SER_DISK, CLIENT_VERSION);
+ CMutableTransaction tx;
+ // Note these tests were originally written with tx.nVersion=1
+ // and the test would be affected by default tx version bumps if not fixed.
+ tx.nVersion = 1;
+ ss << tx;
+ BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 4978c95130..559b3caf1c 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -16,47 +16,17 @@
#include <boost/test/unit_test.hpp>
-using namespace std;
-
-static const string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj");
-static const string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3");
-static const string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw");
-static const string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g");
+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 string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");
-
-
-#ifdef KEY_TESTS_DUMPINFO
-void dumpKeyInfo(uint256 privkey)
-{
- CKey key;
- key.resize(32);
- memcpy(&secret[0], &privkey, 32);
- 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);
- 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)
@@ -111,12 +81,12 @@ BOOST_AUTO_TEST_CASE(key_test1)
for (int n=0; n<16; n++)
{
- string strMsg = strprintf("Very secret message %i: 11", n);
+ std::string strMsg = strprintf("Very secret message %i: 11", n);
uint256 hashMsg = Hash(strMsg.begin(), strMsg.end());
// normal signatures
- vector<unsigned char> sign1, sign2, sign1C, sign2C;
+ std::vector<unsigned char> sign1, sign2, sign1C, sign2C;
BOOST_CHECK(key1.Sign (hashMsg, sign1));
BOOST_CHECK(key2.Sign (hashMsg, sign2));
@@ -145,7 +115,7 @@ BOOST_AUTO_TEST_CASE(key_test1)
// compact signatures (with key recovery)
- vector<unsigned char> csign1, csign2, csign1C, csign2C;
+ std::vector<unsigned char> csign1, csign2, csign1C, csign2C;
BOOST_CHECK(key1.SignCompact (hashMsg, csign1));
BOOST_CHECK(key2.SignCompact (hashMsg, csign2));
@@ -168,7 +138,7 @@ BOOST_AUTO_TEST_CASE(key_test1)
// test deterministic signing
std::vector<unsigned char> detsig, detsigc;
- string strMsg = "Very deterministic message";
+ std::string strMsg = "Very deterministic message";
uint256 hashMsg = Hash(strMsg.begin(), strMsg.end());
BOOST_CHECK(key1.Sign(hashMsg, detsig));
BOOST_CHECK(key1C.Sign(hashMsg, detsigc));
diff --git a/src/test/limitedmap_tests.cpp b/src/test/limitedmap_tests.cpp
index faaddffad8..b071ab117b 100644
--- a/src/test/limitedmap_tests.cpp
+++ b/src/test/limitedmap_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -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
@@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(limitedmap_test)
// make sure the item is present
BOOST_CHECK(map.count(i) == 1);
- // use the iterator to check for the expected key adn value
+ // use the iterator to check for the expected key and value
BOOST_CHECK(it->first == i);
BOOST_CHECK(it->second == i + 1);
diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp
index dbfbdd934f..656aec606b 100644
--- a/src/test/main_tests.cpp
+++ b/src/test/main_tests.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Copyright (c) 2014-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 "chainparams.h"
-#include "main.h"
+#include "validation.h"
+#include "net.h"
#include "test/test_bitcoin.h"
@@ -38,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 033a50f94f..51b28d09fa 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -54,18 +54,18 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
}
- CTxMemPool testPool(CFeeRate(0));
- std::list<CTransaction> removed;
+ CTxMemPool testPool;
// Nothing in pool, remove should do nothing:
- testPool.removeRecursive(txParent, removed);
- BOOST_CHECK_EQUAL(removed.size(), 0);
+ unsigned int poolSize = testPool.size();
+ testPool.removeRecursive(txParent);
+ BOOST_CHECK_EQUAL(testPool.size(), poolSize);
// Just the parent:
testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent));
- testPool.removeRecursive(txParent, removed);
- BOOST_CHECK_EQUAL(removed.size(), 1);
- removed.clear();
+ poolSize = testPool.size();
+ testPool.removeRecursive(txParent);
+ BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1);
// Parent, children, grandchildren:
testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent));
@@ -75,19 +75,21 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i]));
}
// Remove Child[0], GrandChild[0] should be removed:
- testPool.removeRecursive(txChild[0], removed);
- BOOST_CHECK_EQUAL(removed.size(), 2);
- removed.clear();
+ poolSize = testPool.size();
+ testPool.removeRecursive(txChild[0]);
+ BOOST_CHECK_EQUAL(testPool.size(), poolSize - 2);
// ... make sure grandchild and child are gone:
- testPool.removeRecursive(txGrandChild[0], removed);
- BOOST_CHECK_EQUAL(removed.size(), 0);
- testPool.removeRecursive(txChild[0], removed);
- BOOST_CHECK_EQUAL(removed.size(), 0);
+ poolSize = testPool.size();
+ testPool.removeRecursive(txGrandChild[0]);
+ BOOST_CHECK_EQUAL(testPool.size(), poolSize);
+ poolSize = testPool.size();
+ testPool.removeRecursive(txChild[0]);
+ BOOST_CHECK_EQUAL(testPool.size(), poolSize);
// Remove parent, all children/grandchildren should go:
- testPool.removeRecursive(txParent, removed);
- BOOST_CHECK_EQUAL(removed.size(), 5);
+ poolSize = testPool.size();
+ testPool.removeRecursive(txParent);
+ BOOST_CHECK_EQUAL(testPool.size(), poolSize - 5);
BOOST_CHECK_EQUAL(testPool.size(), 0);
- removed.clear();
// Add children and grandchildren, but NOT the parent (simulate the parent being in a block)
for (int i = 0; i < 3; i++)
@@ -97,10 +99,10 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
}
// Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be
// put into the mempool (maybe because it is non-standard):
- testPool.removeRecursive(txParent, removed);
- BOOST_CHECK_EQUAL(removed.size(), 6);
+ poolSize = testPool.size();
+ testPool.removeRecursive(txParent);
+ BOOST_CHECK_EQUAL(testPool.size(), poolSize - 6);
BOOST_CHECK_EQUAL(testPool.size(), 0);
- removed.clear();
}
template<typename name>
@@ -116,37 +118,36 @@ void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder)
BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
- entry.hadNoDependencies = true;
/* 3rd highest fee */
CMutableTransaction tx1 = CMutableTransaction();
tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx1.GetHash(), 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();
@@ -154,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);
@@ -281,12 +281,11 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
BOOST_CHECK_EQUAL(pool.size(), 10);
// Now try removing tx10 and verify the sort order returns to normal
- std::list<CTransaction> removed;
- pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx(), removed);
+ pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx());
CheckSort<descendant_score>(pool, snapshotOrder);
- pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx(), removed);
- pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx(), removed);
+ pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx());
+ pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx());
/* Now check the sort on the mining score index.
* Final order should be:
*
@@ -320,23 +319,22 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
- entry.hadNoDependencies = true;
/* 3rd highest fee */
CMutableTransaction tx1 = CMutableTransaction();
tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx1.GetHash(), 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 */
@@ -344,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();
@@ -389,7 +387,12 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6));
BOOST_CHECK_EQUAL(pool.size(), 6);
- sortedOrder.push_back(tx6.GetHash().ToString());
+ // Ties are broken by hash
+ if (tx3.GetHash() < tx6.GetHash())
+ sortedOrder.push_back(tx6.GetHash().ToString());
+ else
+ sortedOrder.insert(sortedOrder.end()-1,tx6.GetHash().ToString());
+
CheckSort<ancestor_score>(pool, sortedOrder);
CMutableTransaction tx7 = CMutableTransaction();
@@ -404,20 +407,22 @@ 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());
CheckSort<ancestor_score>(pool, sortedOrder);
/* after tx6 is mined, tx7 should move up in the sort */
- std::vector<CTransaction> vtx;
- vtx.push_back(tx6);
- std::list<CTransaction> dummy;
- pool.removeForBlock(vtx, 1, dummy, false);
+ std::vector<CTransactionRef> vtx;
+ vtx.push_back(MakeTransactionRef(tx6));
+ pool.removeForBlock(vtx, 1);
sortedOrder.erase(sortedOrder.begin()+1);
- sortedOrder.pop_back();
+ // Ties are broken by hash
+ if (tx3.GetHash() < tx6.GetHash())
+ sortedOrder.pop_back();
+ else
+ sortedOrder.erase(sortedOrder.end()-2);
sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString());
CheckSort<ancestor_score>(pool, sortedOrder);
}
@@ -425,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);
@@ -435,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);
@@ -443,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()));
@@ -453,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);
@@ -461,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()));
@@ -524,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);
@@ -536,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()));
@@ -545,16 +549,15 @@ 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<CTransaction> vtx;
- std::list<CTransaction> conflicts;
+ std::vector<CTransactionRef> vtx;
SetMockTime(42);
SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE);
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
// ... we should keep the same min fee until we get a block
- pool.removeForBlock(vtx, 1, conflicts);
+ pool.removeForBlock(vtx, 1);
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE);
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/2);
// ... then feerate should drop 1/2 each halflife
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index b40ab848dc..f2f06fa8e2 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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 "consensus/merkle.h"
#include "test/test_bitcoin.h"
-#include "random.h"
+#include "test/test_random.h"
#include <boost/test/unit_test.hpp>
@@ -15,8 +15,8 @@ static uint256 BlockBuildMerkleTree(const CBlock& block, bool* fMutated, std::ve
{
vMerkleTree.clear();
vMerkleTree.reserve(block.vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
- for (std::vector<CTransaction>::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it)
- vMerkleTree.push_back(it->GetHash());
+ for (std::vector<CTransactionRef>::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it)
+ vMerkleTree.push_back((*it)->GetHash());
int j = 0;
bool mutated = false;
for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
@@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(merkle_test)
for (int j = 0; j < ntx; j++) {
CMutableTransaction mtx;
mtx.nLockTime = j;
- block.vtx[j] = mtx;
+ block.vtx[j] = MakeTransactionRef(std::move(mtx));
}
// Compute the root of the block before mutating it.
bool unmutatedMutated = false;
@@ -118,7 +118,7 @@ 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;
@@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(merkle_test)
std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx);
std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx);
BOOST_CHECK(oldBranch == newBranch);
- BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx].GetHash(), newBranch, mtx) == oldRoot);
+ BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx]->GetHash(), newBranch, mtx) == oldRoot);
}
}
}
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index fd581db52e..fadff612d4 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -7,8 +7,9 @@
#include "consensus/consensus.h"
#include "consensus/merkle.h"
#include "consensus/validation.h"
-#include "main.h"
+#include "validation.h"
#include "miner.h"
+#include "policy/policy.h"
#include "pubkey.h"
#include "script/standard.h"
#include "txmempool.h"
@@ -18,10 +19,23 @@
#include "test/test_bitcoin.h"
+#include <memory>
+
#include <boost/test/unit_test.hpp>
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.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
+ options.blockMinFeeRate = blockMinFeeRate;
+ return BlockAssembler(params, options);
+}
+
static
struct {
unsigned char extranonce;
@@ -74,8 +88,7 @@ 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<CTransaction *>& txFirst)
+void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, std::vector<CTransactionRef>& txFirst)
{
// Test the ancestor feerate transaction selection.
TestMemPoolEntryHelper entry;
@@ -105,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));
- CBlockTemplate *pblocktemplate = BlockAssembler(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);
+ 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();
@@ -118,31 +131,30 @@ 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);
- BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashLowFeeTx);
+ BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx);
+ BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx);
}
// Test that packages above the min relay fee do get included, even if one
// of the transactions is below the min relay fee
// Remove the low fee transaction and replace with a higher fee transaction
- std::list<CTransaction> dummy;
- mempool.removeRecursive(tx, dummy);
+ mempool.removeRecursive(tx);
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);
- BOOST_CHECK(pblocktemplate->block.vtx[4].GetHash() == hashFreeTx);
- BOOST_CHECK(pblocktemplate->block.vtx[5].GetHash() == hashLowFeeTx);
+ pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx);
+ BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx);
// Test that transaction selection properly updates ancestor fee
// calculations as ancestor transactions get included in a block.
@@ -157,16 +169,16 @@ 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) {
- BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashFreeTx2);
- BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashLowFeeTx2);
+ BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx2);
+ BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx2);
}
// This tx will be mineable, and should cause hashLowFeeTx2 to be selected
@@ -174,65 +186,61 @@ 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);
- BOOST_CHECK(pblocktemplate->block.vtx[8].GetHash() == hashLowFeeTx2);
+ pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);
}
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
- // Disable size accounting (CPFP does not support it)
- mapArgs["-blockmaxsize"] = strprintf("%u", MAX_BLOCK_SERIALIZED_SIZE);
-
- const CChainParams& chainparams = Params(CBaseChainParams::MAIN);
+ // Note that by default, these tests run with size accounting enabled.
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
+ const CChainParams& chainparams = *chainParams;
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
- CBlockTemplate *pblocktemplate;
+ std::unique_ptr<CBlockTemplate> pblocktemplate;
CMutableTransaction tx,tx2;
CScript script;
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 :)
int baseheight = 0;
- std::vector<CTransaction*>txFirst;
+ std::vector<CTransactionRef> txFirst;
for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i)
{
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
- CMutableTransaction txCoinbase(pblock->vtx[0]);
+ CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.nVersion = 1;
txCoinbase.vin[0].scriptSig = CScript();
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
+ txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
txCoinbase.vout[0].scriptPubKey = CScript();
- pblock->vtx[0] = CTransaction(txCoinbase);
+ pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
if (txFirst.size() == 0)
baseheight = chainActive.Height();
if (txFirst.size() < 4)
- txFirst.push_back(new CTransaction(pblock->vtx[0]));
+ txFirst.push_back(pblock->vtx[0]);
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
pblock->nNonce = blockinfo[i].nonce;
- CValidationState state;
- BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL));
- BOOST_CHECK(state.IsValid());
+ std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
+ BOOST_CHECK(ProcessNewBlock(chainparams, shared_pblock, true, NULL));
pblock->hashPrevBlock = pblock->GetHash();
}
- delete pblocktemplate;
// Just to make sure we can still make simple blocks
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
- delete pblocktemplate;
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
const CAmount BLOCKSUBSIDY = 50*COIN;
const CAmount LOWFEE = CENT;
@@ -256,7 +264,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
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();
@@ -270,8 +278,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
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));
- delete pblocktemplate;
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
mempool.clear();
// block size > limit
@@ -291,17 +298,16 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
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));
- delete pblocktemplate;
+ 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;
@@ -315,8 +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));
- delete pblocktemplate;
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
mempool.clear();
// coinbase in mempool, template creation fails
@@ -327,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
@@ -344,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
@@ -357,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
@@ -373,8 +378,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
next->BuildSkip();
chainActive.SetTip(next);
}
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
- delete pblocktemplate;
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
// Extend to a 210000-long block chain.
while (chainActive.Tip()->nHeight < 210000) {
CBlockIndex* prev = chainActive.Tip();
@@ -386,8 +390,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
next->BuildSkip();
chainActive.SetTip(next);
}
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
- delete pblocktemplate;
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
// Delete the dummy blocks again.
while (chainActive.Tip()->nHeight > nHeight) {
CBlockIndex* del = chainActive.Tip();
@@ -473,23 +476,21 @@ 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,
// but relative locked txs will if inconsistently added to mempool.
// For now these will still generate a valid template until BIP68 soft fork
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3);
- delete pblocktemplate;
// However if we advance height by 1 and time by 512, all of them should be mined
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++)
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast
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);
- delete pblocktemplate;
chainActive.Tip()->nHeight--;
SetMockTime(0);
@@ -497,9 +498,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
TestPackageSelection(chainparams, scriptPubKey, txFirst);
- BOOST_FOREACH(CTransaction *_tx, txFirst)
- delete _tx;
-
fCheckpointsEnabled = true;
}
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 581b0cee1e..dd5678ea6e 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2014 The Bitcoin Core developers
+// 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.
@@ -17,14 +17,12 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-using namespace std;
-
-typedef vector<unsigned char> valtype;
+typedef std::vector<unsigned char> valtype;
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
CScript
-sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn)
+sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction, int whichIn)
{
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SIGVERSION_BASE);
@@ -32,7 +30,7 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction,
result << OP_0; // CHECKMULTISIG bug workaround
BOOST_FOREACH(const CKey &key, keys)
{
- vector<unsigned char> vchSig;
+ std::vector<unsigned char> vchSig;
BOOST_CHECK(key.Sign(hash, vchSig));
vchSig.push_back((unsigned char)SIGHASH_ALL);
result << vchSig;
@@ -75,7 +73,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
txTo[i].vout[0].nValue = 1;
}
- vector<CKey> keys;
+ std::vector<CKey> keys;
CScript s;
// Test a AND b:
@@ -200,7 +198,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
partialkeystore.AddKey(key[0]);
{
- vector<valtype> solutions;
+ std::vector<valtype> solutions;
txnouttype whichType;
CScript s;
s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
@@ -213,7 +211,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
BOOST_CHECK(!IsMine(emptykeystore, s));
}
{
- vector<valtype> solutions;
+ std::vector<valtype> solutions;
txnouttype whichType;
CScript s;
s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
@@ -226,7 +224,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
BOOST_CHECK(!IsMine(emptykeystore, s));
}
{
- vector<valtype> solutions;
+ std::vector<valtype> solutions;
txnouttype whichType;
CScript s;
s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
@@ -239,13 +237,13 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
BOOST_CHECK(!IsMine(partialkeystore, s));
}
{
- vector<valtype> solutions;
+ 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);
- vector<CTxDestination> addrs;
+ std::vector<CTxDestination> addrs;
int nRequired;
BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired));
BOOST_CHECK(addrs[0] == keyaddr[0]);
@@ -256,7 +254,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
BOOST_CHECK(!IsMine(partialkeystore, s));
}
{
- vector<valtype> solutions;
+ 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;
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index d005d6a163..0c7f3e5e23 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -9,36 +9,36 @@
#include "serialize.h"
#include "streams.h"
#include "net.h"
+#include "netbase.h"
#include "chainparams.h"
-
-using namespace std;
+#include "util.h"
class CAddrManSerializationMock : public CAddrMan
{
public:
- virtual void Serialize(CDataStream& s, int nType, int nVersionDummy) const = 0;
+ virtual void Serialize(CDataStream& s) const = 0;
//! Ensure that bucket placement is always the same for testing purposes.
void MakeDeterministic()
{
nKey.SetNull();
- seed_insecure_rand(true);
+ insecure_rand = FastRandomContext(true);
}
};
class CAddrManUncorrupted : public CAddrManSerializationMock
{
public:
- void Serialize(CDataStream& s, int nType, int nVersionDummy) const
+ void Serialize(CDataStream& s) const
{
- CAddrMan::Serialize(s, nType, nVersionDummy);
+ CAddrMan::Serialize(s);
}
};
class CAddrManCorrupted : public CAddrManSerializationMock
{
public:
- void Serialize(CDataStream& s, int nType, int nVersionDummy) const
+ void Serialize(CDataStream& s) const
{
// Produces corrupt output that claims addrman has 20 addrs when it only has one addr.
unsigned char nVersion = 1;
@@ -51,37 +51,56 @@ public:
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
s << nUBuckets;
- CAddress addr = CAddress(CService("252.1.1.1", 7777), NODE_NONE);
- CAddrInfo info = CAddrInfo(addr, CNetAddr("252.2.2.2"));
+ CService serv;
+ Lookup("252.1.1.1", serv, 7777, false);
+ CAddress addr = CAddress(serv, NODE_NONE);
+ CNetAddr resolved;
+ LookupHost("252.2.2.2", resolved, false);
+ CAddrInfo info = CAddrInfo(addr, resolved);
s << info;
}
};
-CDataStream AddrmanToStream(CAddrManSerializationMock& addrman)
+CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman)
{
CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
ssPeersIn << FLATDATA(Params().MessageStart());
- ssPeersIn << addrman;
+ ssPeersIn << _addrman;
std::string str = ssPeersIn.str();
- vector<unsigned char> vchData(str.begin(), str.end());
+ std::vector<unsigned char> vchData(str.begin(), str.end());
return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
}
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;
+ SoftSetArg("-port", std::to_string(altPort));
+ port = GetListenPort();
+ BOOST_CHECK(port == altPort);
+}
+
BOOST_AUTO_TEST_CASE(caddrdb_read)
{
CAddrManUncorrupted addrmanUncorrupted;
addrmanUncorrupted.MakeDeterministic();
- CService addr1 = CService("250.7.1.1", 8333);
- CService addr2 = CService("250.7.2.2", 9999);
- CService addr3 = CService("250.7.3.3", 9999);
+ CService addr1, addr2, addr3;
+ Lookup("250.7.1.1", addr1, 8333, false);
+ Lookup("250.7.2.2", addr2, 9999, false);
+ Lookup("250.7.3.3", addr3, 9999, false);
// Add three addresses to new table.
- addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), CService("252.5.1.1", 8333));
- addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), CService("252.5.1.1", 8333));
- addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), CService("252.5.1.1", 8333));
+ CService source;
+ Lookup("252.5.1.1", source, 8333, false);
+ addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), source);
+ addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), source);
+ addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), source);
// Test that the de-serialization does not throw an exception.
CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
@@ -142,4 +161,28 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
BOOST_CHECK(addrman2.size() == 0);
}
+BOOST_AUTO_TEST_CASE(cnode_simple_test)
+{
+ SOCKET hSocket = INVALID_SOCKET;
+ NodeId id = 0;
+ int height = 0;
+
+ in_addr ipv4Addr;
+ ipv4Addr.s_addr = 0xa0b0c001;
+
+ CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
+ std::string pszDest = "";
+ bool fInboundIn = false;
+
+ // Test that fFeeler is false by default.
+ std::unique_ptr<CNode> pnode1(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, pszDest, fInboundIn));
+ BOOST_CHECK(pnode1->fInbound == false);
+ BOOST_CHECK(pnode1->fFeeler == false);
+
+ fInboundIn = true;
+ std::unique_ptr<CNode> pnode2(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, pszDest, fInboundIn));
+ BOOST_CHECK(pnode2->fInbound == true);
+ BOOST_CHECK(pnode2->fFeeler == false);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 4168f75e9a..1afef5b1ce 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -10,46 +10,61 @@
#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
-using namespace std;
-
BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup)
+static CNetAddr ResolveIP(const char* ip)
+{
+ CNetAddr addr;
+ LookupHost(ip, addr, false);
+ return addr;
+}
+
+static CSubNet ResolveSubNet(const char* subnet)
+{
+ CSubNet ret;
+ LookupSubNet(subnet, ret);
+ return ret;
+}
+
BOOST_AUTO_TEST_CASE(netbase_networks)
{
- BOOST_CHECK(CNetAddr("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
- BOOST_CHECK(CNetAddr("::1").GetNetwork() == NET_UNROUTABLE);
- BOOST_CHECK(CNetAddr("8.8.8.8").GetNetwork() == NET_IPV4);
- BOOST_CHECK(CNetAddr("2001::8888").GetNetwork() == NET_IPV6);
- BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR);
+ BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
+ BOOST_CHECK(ResolveIP("::1").GetNetwork() == NET_UNROUTABLE);
+ 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_AUTO_TEST_CASE(netbase_properties)
{
- BOOST_CHECK(CNetAddr("127.0.0.1").IsIPv4());
- BOOST_CHECK(CNetAddr("::FFFF:192.168.1.1").IsIPv4());
- BOOST_CHECK(CNetAddr("::1").IsIPv6());
- BOOST_CHECK(CNetAddr("10.0.0.1").IsRFC1918());
- BOOST_CHECK(CNetAddr("192.168.1.1").IsRFC1918());
- BOOST_CHECK(CNetAddr("172.31.255.255").IsRFC1918());
- BOOST_CHECK(CNetAddr("2001:0DB8::").IsRFC3849());
- BOOST_CHECK(CNetAddr("169.254.1.1").IsRFC3927());
- BOOST_CHECK(CNetAddr("2002::1").IsRFC3964());
- BOOST_CHECK(CNetAddr("FC00::").IsRFC4193());
- BOOST_CHECK(CNetAddr("2001::2").IsRFC4380());
- BOOST_CHECK(CNetAddr("2001:10::").IsRFC4843());
- BOOST_CHECK(CNetAddr("FE80::").IsRFC4862());
- BOOST_CHECK(CNetAddr("64:FF9B::").IsRFC6052());
- BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor());
- BOOST_CHECK(CNetAddr("127.0.0.1").IsLocal());
- BOOST_CHECK(CNetAddr("::1").IsLocal());
- BOOST_CHECK(CNetAddr("8.8.8.8").IsRoutable());
- BOOST_CHECK(CNetAddr("2001::1").IsRoutable());
- BOOST_CHECK(CNetAddr("127.0.0.1").IsValid());
+
+ BOOST_CHECK(ResolveIP("127.0.0.1").IsIPv4());
+ BOOST_CHECK(ResolveIP("::FFFF:192.168.1.1").IsIPv4());
+ BOOST_CHECK(ResolveIP("::1").IsIPv6());
+ BOOST_CHECK(ResolveIP("10.0.0.1").IsRFC1918());
+ BOOST_CHECK(ResolveIP("192.168.1.1").IsRFC1918());
+ BOOST_CHECK(ResolveIP("172.31.255.255").IsRFC1918());
+ BOOST_CHECK(ResolveIP("2001:0DB8::").IsRFC3849());
+ BOOST_CHECK(ResolveIP("169.254.1.1").IsRFC3927());
+ BOOST_CHECK(ResolveIP("2002::1").IsRFC3964());
+ BOOST_CHECK(ResolveIP("FC00::").IsRFC4193());
+ BOOST_CHECK(ResolveIP("2001::2").IsRFC4380());
+ BOOST_CHECK(ResolveIP("2001:10::").IsRFC4843());
+ BOOST_CHECK(ResolveIP("FE80::").IsRFC4862());
+ BOOST_CHECK(ResolveIP("64:FF9B::").IsRFC6052());
+ BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor());
+ BOOST_CHECK(ResolveIP("127.0.0.1").IsLocal());
+ BOOST_CHECK(ResolveIP("::1").IsLocal());
+ BOOST_CHECK(ResolveIP("8.8.8.8").IsRoutable());
+ BOOST_CHECK(ResolveIP("2001::1").IsRoutable());
+ BOOST_CHECK(ResolveIP("127.0.0.1").IsValid());
+
}
-bool static TestSplitHost(string test, string host, int port)
+bool static TestSplitHost(std::string test, std::string host, int port)
{
- string hostOut;
+ std::string hostOut;
int portOut = -1;
SplitHostPort(test, portOut, hostOut);
return hostOut == host && port == portOut;
@@ -74,11 +89,9 @@ BOOST_AUTO_TEST_CASE(netbase_splithost)
BOOST_CHECK(TestSplitHost("", "", -1));
}
-bool static TestParse(string src, string canon)
+bool static TestParse(std::string src, std::string canon)
{
- CService addr;
- if (!LookupNumeric(src.c_str(), addr, 65535))
- return canon == "";
+ CService addr(LookupNumeric(src.c_str(), 65535));
return canon == addr.ToString();
}
@@ -90,165 +103,185 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
BOOST_CHECK(TestParse("::", "[::]:65535"));
BOOST_CHECK(TestParse("[::]:8333", "[::]:8333"));
BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535"));
- BOOST_CHECK(TestParse(":::", ""));
+ BOOST_CHECK(TestParse(":::", "[::]:0"));
}
BOOST_AUTO_TEST_CASE(onioncat_test)
{
+
// values from https://web.archive.org/web/20121122003543/http://www.cypherpunk.at/onioncat/wiki/OnionCat
- CNetAddr addr1("5wyqrzbvrdsumnok.onion");
- CNetAddr addr2("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca");
+ CNetAddr addr1(ResolveIP("5wyqrzbvrdsumnok.onion"));
+ CNetAddr addr2(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca"));
BOOST_CHECK(addr1 == addr2);
BOOST_CHECK(addr1.IsTor());
BOOST_CHECK(addr1.ToStringIP() == "5wyqrzbvrdsumnok.onion");
BOOST_CHECK(addr1.IsRoutable());
+
}
BOOST_AUTO_TEST_CASE(subnet_test)
{
- BOOST_CHECK(CSubNet("1.2.3.0/24") == CSubNet("1.2.3.0/255.255.255.0"));
- BOOST_CHECK(CSubNet("1.2.3.0/24") != CSubNet("1.2.4.0/255.255.255.0"));
- BOOST_CHECK(CSubNet("1.2.3.0/24").Match(CNetAddr("1.2.3.4")));
- BOOST_CHECK(!CSubNet("1.2.2.0/24").Match(CNetAddr("1.2.3.4")));
- BOOST_CHECK(CSubNet("1.2.3.4").Match(CNetAddr("1.2.3.4")));
- BOOST_CHECK(CSubNet("1.2.3.4/32").Match(CNetAddr("1.2.3.4")));
- BOOST_CHECK(!CSubNet("1.2.3.4").Match(CNetAddr("5.6.7.8")));
- BOOST_CHECK(!CSubNet("1.2.3.4/32").Match(CNetAddr("5.6.7.8")));
- BOOST_CHECK(CSubNet("::ffff:127.0.0.1").Match(CNetAddr("127.0.0.1")));
- BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:8")));
- BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:9")));
- BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:0/112").Match(CNetAddr("1:2:3:4:5:6:7:1234")));
- BOOST_CHECK(CSubNet("192.168.0.1/24").Match(CNetAddr("192.168.0.2")));
- BOOST_CHECK(CSubNet("192.168.0.20/29").Match(CNetAddr("192.168.0.18")));
- BOOST_CHECK(CSubNet("1.2.2.1/24").Match(CNetAddr("1.2.2.4")));
- BOOST_CHECK(CSubNet("1.2.2.110/31").Match(CNetAddr("1.2.2.111")));
- BOOST_CHECK(CSubNet("1.2.2.20/26").Match(CNetAddr("1.2.2.63")));
+
+ BOOST_CHECK(ResolveSubNet("1.2.3.0/24") == ResolveSubNet("1.2.3.0/255.255.255.0"));
+ BOOST_CHECK(ResolveSubNet("1.2.3.0/24") != ResolveSubNet("1.2.4.0/255.255.255.0"));
+ BOOST_CHECK(ResolveSubNet("1.2.3.0/24").Match(ResolveIP("1.2.3.4")));
+ BOOST_CHECK(!ResolveSubNet("1.2.2.0/24").Match(ResolveIP("1.2.3.4")));
+ BOOST_CHECK(ResolveSubNet("1.2.3.4").Match(ResolveIP("1.2.3.4")));
+ BOOST_CHECK(ResolveSubNet("1.2.3.4/32").Match(ResolveIP("1.2.3.4")));
+ BOOST_CHECK(!ResolveSubNet("1.2.3.4").Match(ResolveIP("5.6.7.8")));
+ BOOST_CHECK(!ResolveSubNet("1.2.3.4/32").Match(ResolveIP("5.6.7.8")));
+ BOOST_CHECK(ResolveSubNet("::ffff:127.0.0.1").Match(ResolveIP("127.0.0.1")));
+ BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8").Match(ResolveIP("1:2:3:4:5:6:7:8")));
+ BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8").Match(ResolveIP("1:2:3:4:5:6:7:9")));
+ BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:0/112").Match(ResolveIP("1:2:3:4:5:6:7:1234")));
+ BOOST_CHECK(ResolveSubNet("192.168.0.1/24").Match(ResolveIP("192.168.0.2")));
+ BOOST_CHECK(ResolveSubNet("192.168.0.20/29").Match(ResolveIP("192.168.0.18")));
+ BOOST_CHECK(ResolveSubNet("1.2.2.1/24").Match(ResolveIP("1.2.2.4")));
+ BOOST_CHECK(ResolveSubNet("1.2.2.110/31").Match(ResolveIP("1.2.2.111")));
+ BOOST_CHECK(ResolveSubNet("1.2.2.20/26").Match(ResolveIP("1.2.2.63")));
// All-Matching IPv6 Matches arbitrary IPv4 and IPv6
- BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1:2:3:4:5:6:7:1234")));
- BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1.2.3.4")));
+ BOOST_CHECK(ResolveSubNet("::/0").Match(ResolveIP("1:2:3:4:5:6:7:1234")));
+ BOOST_CHECK(ResolveSubNet("::/0").Match(ResolveIP("1.2.3.4")));
// All-Matching IPv4 does not Match IPv6
- BOOST_CHECK(!CSubNet("0.0.0.0/0").Match(CNetAddr("1:2:3:4:5:6:7:1234")));
+ BOOST_CHECK(!ResolveSubNet("0.0.0.0/0").Match(ResolveIP("1:2:3:4:5:6:7:1234")));
// Invalid subnets Match nothing (not even invalid addresses)
- BOOST_CHECK(!CSubNet().Match(CNetAddr("1.2.3.4")));
- BOOST_CHECK(!CSubNet("").Match(CNetAddr("4.5.6.7")));
- BOOST_CHECK(!CSubNet("bloop").Match(CNetAddr("0.0.0.0")));
- BOOST_CHECK(!CSubNet("bloop").Match(CNetAddr("hab")));
+ BOOST_CHECK(!CSubNet().Match(ResolveIP("1.2.3.4")));
+ BOOST_CHECK(!ResolveSubNet("").Match(ResolveIP("4.5.6.7")));
+ BOOST_CHECK(!ResolveSubNet("bloop").Match(ResolveIP("0.0.0.0")));
+ BOOST_CHECK(!ResolveSubNet("bloop").Match(ResolveIP("hab")));
// Check valid/invalid
- BOOST_CHECK(CSubNet("1.2.3.0/0").IsValid());
- BOOST_CHECK(!CSubNet("1.2.3.0/-1").IsValid());
- BOOST_CHECK(CSubNet("1.2.3.0/32").IsValid());
- BOOST_CHECK(!CSubNet("1.2.3.0/33").IsValid());
- BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/0").IsValid());
- BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/33").IsValid());
- BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8/-1").IsValid());
- BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/128").IsValid());
- BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8/129").IsValid());
- BOOST_CHECK(!CSubNet("fuzzy").IsValid());
+ BOOST_CHECK(ResolveSubNet("1.2.3.0/0").IsValid());
+ BOOST_CHECK(!ResolveSubNet("1.2.3.0/-1").IsValid());
+ BOOST_CHECK(ResolveSubNet("1.2.3.0/32").IsValid());
+ BOOST_CHECK(!ResolveSubNet("1.2.3.0/33").IsValid());
+ BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/0").IsValid());
+ BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/33").IsValid());
+ BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8/-1").IsValid());
+ BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/128").IsValid());
+ BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8/129").IsValid());
+ BOOST_CHECK(!ResolveSubNet("fuzzy").IsValid());
//CNetAddr constructor test
- BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).IsValid());
- BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).Match(CNetAddr("127.0.0.1")));
- BOOST_CHECK(!CSubNet(CNetAddr("127.0.0.1")).Match(CNetAddr("127.0.0.2")));
- BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).ToString() == "127.0.0.1/32");
+ BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).IsValid());
+ BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).Match(ResolveIP("127.0.0.1")));
+ BOOST_CHECK(!CSubNet(ResolveIP("127.0.0.1")).Match(ResolveIP("127.0.0.2")));
+ BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).ToString() == "127.0.0.1/32");
+
+ CSubNet subnet = CSubNet(ResolveIP("1.2.3.4"), 32);
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
+ subnet = CSubNet(ResolveIP("1.2.3.4"), 8);
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8");
+ subnet = CSubNet(ResolveIP("1.2.3.4"), 0);
+ BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0");
+
+ subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("255.255.255.255"));
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
+ subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("255.0.0.0"));
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8");
+ subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("0.0.0.0"));
+ BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0");
- BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).IsValid());
- BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).Match(CNetAddr("1:2:3:4:5:6:7:8")));
- BOOST_CHECK(!CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).Match(CNetAddr("1:2:3:4:5:6:7:9")));
- BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).ToString() == "1:2:3:4:5:6:7:8/128");
+ BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).IsValid());
+ BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).Match(ResolveIP("1:2:3:4:5:6:7:8")));
+ BOOST_CHECK(!CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).Match(ResolveIP("1:2:3:4:5:6:7:9")));
+ BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).ToString() == "1:2:3:4:5:6:7:8/128");
- CSubNet subnet = CSubNet("1.2.3.4/255.255.255.255");
+ subnet = ResolveSubNet("1.2.3.4/255.255.255.255");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
- subnet = CSubNet("1.2.3.4/255.255.255.254");
+ subnet = ResolveSubNet("1.2.3.4/255.255.255.254");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/31");
- subnet = CSubNet("1.2.3.4/255.255.255.252");
+ subnet = ResolveSubNet("1.2.3.4/255.255.255.252");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/30");
- subnet = CSubNet("1.2.3.4/255.255.255.248");
+ subnet = ResolveSubNet("1.2.3.4/255.255.255.248");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/29");
- subnet = CSubNet("1.2.3.4/255.255.255.240");
+ subnet = ResolveSubNet("1.2.3.4/255.255.255.240");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/28");
- subnet = CSubNet("1.2.3.4/255.255.255.224");
+ subnet = ResolveSubNet("1.2.3.4/255.255.255.224");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/27");
- subnet = CSubNet("1.2.3.4/255.255.255.192");
+ subnet = ResolveSubNet("1.2.3.4/255.255.255.192");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/26");
- subnet = CSubNet("1.2.3.4/255.255.255.128");
+ subnet = ResolveSubNet("1.2.3.4/255.255.255.128");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/25");
- subnet = CSubNet("1.2.3.4/255.255.255.0");
+ subnet = ResolveSubNet("1.2.3.4/255.255.255.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/24");
- subnet = CSubNet("1.2.3.4/255.255.254.0");
+ subnet = ResolveSubNet("1.2.3.4/255.255.254.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.2.0/23");
- subnet = CSubNet("1.2.3.4/255.255.252.0");
+ subnet = ResolveSubNet("1.2.3.4/255.255.252.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/22");
- subnet = CSubNet("1.2.3.4/255.255.248.0");
+ subnet = ResolveSubNet("1.2.3.4/255.255.248.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/21");
- subnet = CSubNet("1.2.3.4/255.255.240.0");
+ subnet = ResolveSubNet("1.2.3.4/255.255.240.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/20");
- subnet = CSubNet("1.2.3.4/255.255.224.0");
+ subnet = ResolveSubNet("1.2.3.4/255.255.224.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/19");
- subnet = CSubNet("1.2.3.4/255.255.192.0");
+ subnet = ResolveSubNet("1.2.3.4/255.255.192.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/18");
- subnet = CSubNet("1.2.3.4/255.255.128.0");
+ subnet = ResolveSubNet("1.2.3.4/255.255.128.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/17");
- subnet = CSubNet("1.2.3.4/255.255.0.0");
+ subnet = ResolveSubNet("1.2.3.4/255.255.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/16");
- subnet = CSubNet("1.2.3.4/255.254.0.0");
+ subnet = ResolveSubNet("1.2.3.4/255.254.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/15");
- subnet = CSubNet("1.2.3.4/255.252.0.0");
+ subnet = ResolveSubNet("1.2.3.4/255.252.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/14");
- subnet = CSubNet("1.2.3.4/255.248.0.0");
+ subnet = ResolveSubNet("1.2.3.4/255.248.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/13");
- subnet = CSubNet("1.2.3.4/255.240.0.0");
+ subnet = ResolveSubNet("1.2.3.4/255.240.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/12");
- subnet = CSubNet("1.2.3.4/255.224.0.0");
+ subnet = ResolveSubNet("1.2.3.4/255.224.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/11");
- subnet = CSubNet("1.2.3.4/255.192.0.0");
+ subnet = ResolveSubNet("1.2.3.4/255.192.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/10");
- subnet = CSubNet("1.2.3.4/255.128.0.0");
+ subnet = ResolveSubNet("1.2.3.4/255.128.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/9");
- subnet = CSubNet("1.2.3.4/255.0.0.0");
+ subnet = ResolveSubNet("1.2.3.4/255.0.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8");
- subnet = CSubNet("1.2.3.4/254.0.0.0");
+ subnet = ResolveSubNet("1.2.3.4/254.0.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/7");
- subnet = CSubNet("1.2.3.4/252.0.0.0");
+ subnet = ResolveSubNet("1.2.3.4/252.0.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/6");
- subnet = CSubNet("1.2.3.4/248.0.0.0");
+ subnet = ResolveSubNet("1.2.3.4/248.0.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/5");
- subnet = CSubNet("1.2.3.4/240.0.0.0");
+ subnet = ResolveSubNet("1.2.3.4/240.0.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/4");
- subnet = CSubNet("1.2.3.4/224.0.0.0");
+ subnet = ResolveSubNet("1.2.3.4/224.0.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/3");
- subnet = CSubNet("1.2.3.4/192.0.0.0");
+ subnet = ResolveSubNet("1.2.3.4/192.0.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/2");
- subnet = CSubNet("1.2.3.4/128.0.0.0");
+ subnet = ResolveSubNet("1.2.3.4/128.0.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/1");
- subnet = CSubNet("1.2.3.4/0.0.0.0");
+ subnet = ResolveSubNet("1.2.3.4/0.0.0.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0");
- subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+ subnet = ResolveSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/128");
- subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:0000:0000:0000:0000:0000:0000:0000");
+ subnet = ResolveSubNet("1:2:3:4:5:6:7:8/ffff:0000:0000:0000:0000:0000:0000:0000");
BOOST_CHECK_EQUAL(subnet.ToString(), "1::/16");
- subnet = CSubNet("1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000");
+ subnet = ResolveSubNet("1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000");
BOOST_CHECK_EQUAL(subnet.ToString(), "::/0");
- subnet = CSubNet("1.2.3.4/255.255.232.0");
+ subnet = ResolveSubNet("1.2.3.4/255.255.232.0");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/255.255.232.0");
- subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
+ subnet = ResolveSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
+
}
BOOST_AUTO_TEST_CASE(netbase_getgroup)
{
- BOOST_CHECK(CNetAddr("127.0.0.1").GetGroup() == boost::assign::list_of(0)); // Local -> !Routable()
- BOOST_CHECK(CNetAddr("257.0.0.1").GetGroup() == boost::assign::list_of(0)); // !Valid -> !Routable()
- BOOST_CHECK(CNetAddr("10.0.0.1").GetGroup() == boost::assign::list_of(0)); // RFC1918 -> !Routable()
- BOOST_CHECK(CNetAddr("169.254.1.1").GetGroup() == boost::assign::list_of(0)); // RFC3927 -> !Routable()
- BOOST_CHECK(CNetAddr("1.2.3.4").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // IPv4
- BOOST_CHECK(CNetAddr("::FFFF:0:102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC6145
- BOOST_CHECK(CNetAddr("64:FF9B::102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC6052
- BOOST_CHECK(CNetAddr("2002:102:304:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC3964
- BOOST_CHECK(CNetAddr("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC4380
- BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup() == boost::assign::list_of((unsigned char)NET_TOR)(239)); // Tor
- BOOST_CHECK(CNetAddr("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(4)(112)(175)); //he.net
- BOOST_CHECK(CNetAddr("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(32)(1)); //IPv6
+
+ BOOST_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_AUTO_TEST_SUITE_END()
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index 74ffe0cc74..a1cb32019a 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -9,16 +9,14 @@
#include "uint256.h"
#include "arith_uint256.h"
#include "version.h"
-#include "random.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>
-using namespace std;
-
class CPartialMerkleTreeTester : public CPartialMerkleTree
{
public:
@@ -45,14 +43,14 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
for (unsigned int j=0; j<nTx; j++) {
CMutableTransaction tx;
tx.nLockTime = j; // actual transaction data doesn't matter; just make the nLockTime's unique
- block.vtx.push_back(CTransaction(tx));
+ block.vtx.push_back(MakeTransactionRef(std::move(tx)));
}
// calculate actual merkle root and height
uint256 merkleRoot1 = BlockMerkleRoot(block);
std::vector<uint256> vTxid(nTx, uint256());
for (unsigned int j=0; j<nTx; j++)
- vTxid[j] = block.vtx[j].GetHash();
+ vTxid[j] = block.vtx[j]->GetHash();
int nHeight = 1, nTx_ = nTx;
while (nTx_ > 1) {
nTx_ = (nTx_+1)/2;
@@ -122,7 +120,6 @@ BOOST_AUTO_TEST_CASE(pmt_malleability)
std::vector<bool> vMatch = boost::assign::list_of(false)(false)(false)(false)(false)(false)(false)(false)(false)(true)(true)(false);
CPartialMerkleTree tree(vTxid, vMatch);
- std::vector<uint256> vTxid2;
std::vector<unsigned int> vIndex;
BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull());
}
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 5c902387f1..ed6782ea34 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -16,29 +16,22 @@ 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);
- double basepri = 1e6;
CAmount deltaFee(100);
- double deltaPri=5e5;
- std::vector<CAmount> feeV[2];
- std::vector<double> priV[2];
+ std::vector<CAmount> feeV;
- // Populate vectors of increasing fees or priorities
+ // Populate vectors of increasing fees
for (int j = 0; j < 10; j++) {
- //V[0] is for fee transactions
- feeV[0].push_back(basefee * (j+1));
- priV[0].push_back(0);
- //V[1] is for priority transactions
- feeV[1].push_back(CAmount(0));
- priV[1].push_back(basepri * pow(10, j+1));
+ feeV.push_back(basefee * (j+1));
}
// Store the hashes of transactions that have been
- // added to the mempool by their associate fee/pri
+ // added to the mempool by their associate fee
// txHashes[j] is populated with transactions either of
- // fee = basefee * (j+1) OR pri = 10^6 * 10^(j+1)
+ // fee = basefee * (j+1)
std::vector<uint256> txHashes[10];
// Create a transaction template
@@ -46,7 +39,6 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (unsigned int i = 0; i < 128; i++)
garbage.push_back('X');
CMutableTransaction tx;
- std::list<CTransaction> dummyConflicted;
tx.vin.resize(1);
tx.vin[0].scriptSig = garbage;
tx.vout.resize(1);
@@ -54,157 +46,153 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
CFeeRate baseRate(basefee, GetVirtualTransactionSize(tx));
// Create a fake block
- std::vector<CTransaction> block;
+ std::vector<CTransactionRef> block;
int blocknum = 0;
// Loop through 200 blocks
// At a decay .998 and 4 fee transactions per block
// This makes the tx count about 1.33 per bucket, above the 1 threshold
while (blocknum < 200) {
- for (int j = 0; j < 10; j++) { // For each fee/pri multiple
- for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ 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[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool));
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
txHashes[j].push_back(hash);
}
}
- //Create blocks where higher fee/pri txs are included more often
+ //Create blocks where higher fee txs are included more often
for (int h = 0; h <= blocknum%10; h++) {
- // 10/10 blocks add highest fee/pri transactions
+ // 10/10 blocks add highest fee transactions
// 9/10 blocks add 2nd highest and so on until ...
- // 1/10 blocks add lowest fee/pri transactions
+ // 1/10 blocks add lowest fee transactions
while (txHashes[9-h].size()) {
- std::shared_ptr<const CTransaction> ptx = mpool.get(txHashes[9-h].back());
+ CTransactionRef ptx = mpool.get(txHashes[9-h].back());
if (ptx)
- block.push_back(*ptx);
+ block.push_back(ptx);
txHashes[9-h].pop_back();
}
}
- mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+ 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);
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(2) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(3) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
+ BOOST_CHECK(feeEst.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);
+ BOOST_CHECK(feeEst.estimateSmartFee(1, &answerFound, mpool) == feeEst.estimateFee(4) && answerFound == 4);
+ BOOST_CHECK(feeEst.estimateSmartFee(3, &answerFound, mpool) == feeEst.estimateFee(4) && answerFound == 4);
+ BOOST_CHECK(feeEst.estimateSmartFee(4, &answerFound, mpool) == feeEst.estimateFee(4) && answerFound == 4);
+ BOOST_CHECK(feeEst.estimateSmartFee(8, &answerFound, mpool) == feeEst.estimateFee(8) && answerFound == 8);
}
}
std::vector<CAmount> origFeeEst;
- std::vector<double> origPriEst;
// Highest feerate is 10*baseRate and gets in all blocks,
// second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,
// third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,
- // so estimateFee(1) should return 10*baseRate.
+ // so estimateFee(1) would return 10*baseRate but is hardcoded to return failure
// 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());
- origPriEst.push_back(mpool.estimatePriority(i));
- if (i > 1) { // Fee estimates should be monotonically decreasing
+ origFeeEst.push_back(feeEst.estimateFee(i).GetFeePerK());
+ if (i > 2) { // Fee estimates should be monotonically decreasing
BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
- BOOST_CHECK(origPriEst[i-1] <= origPriEst[i-2]);
}
int mult = 11-i;
- BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee);
- BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee);
- BOOST_CHECK(origPriEst[i-1] < pow(10,mult) * basepri + deltaPri);
- BOOST_CHECK(origPriEst[i-1] > pow(10,mult) * basepri - deltaPri);
+ if (i > 1) {
+ 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());
+ }
}
// Mine 50 more blocks with no transactions happening, estimates shouldn't change
// We haven't decayed the moving average enough so we still have enough data points in every bucket
while (blocknum < 250)
- mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+ mpool.removeForBlock(block, ++blocknum);
- for (int i = 1; i < 10;i++) {
- BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
- BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
- BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] + deltaPri);
- BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
+ for (int i = 2; i < 10;i++) {
+ BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
}
// Mine 15 more blocks with lots of transactions happening and not getting mined
// Estimates should go up
while (blocknum < 265) {
- for (int j = 0; j < 10; j++) { // For each fee/pri multiple
- for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ 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[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).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, dummyConflicted);
+ 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(mpool.estimatePriority(i) == -1 || mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
- BOOST_CHECK(mpool.estimateSmartPriority(i, &answerFound) > origPriEst[answerFound-1] - deltaPri);
+ BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(feeEst.estimateSmartFee(i, &answerFound, mpool).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee);
}
// Mine all those transactions
// Estimates should still not be below original
for (int j = 0; j < 10; j++) {
while(txHashes[j].size()) {
- std::shared_ptr<const CTransaction> ptx = mpool.get(txHashes[j].back());
+ CTransactionRef ptx = mpool.get(txHashes[j].back());
if (ptx)
- block.push_back(*ptx);
+ block.push_back(ptx);
txHashes[j].pop_back();
}
}
- mpool.removeForBlock(block, 265, dummyConflicted);
+ mpool.removeForBlock(block, 265);
block.clear();
- for (int i = 1; i < 10;i++) {
- BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
- BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
+ for (int i = 2; i < 10;i++) {
+ BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
}
// Mine 200 more blocks where everything is mined every block
// Estimates should be below original estimates
while (blocknum < 465) {
- for (int j = 0; j < 10; j++) { // For each fee/pri multiple
- for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ 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[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool));
- std::shared_ptr<const CTransaction> ptx = mpool.get(hash);
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
+ CTransactionRef ptx = mpool.get(hash);
if (ptx)
- block.push_back(*ptx);
+ block.push_back(ptx);
+
}
}
- mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+ mpool.removeForBlock(block, ++blocknum);
block.clear();
}
- for (int i = 1; i < 10; i++) {
- BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
- BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] - deltaPri);
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
+ for (int i = 2; i < 10; i++) {
+ BOOST_CHECK(feeEst.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[0][5]).Time(GetTime()).Priority(priV[1][5]).Height(blocknum).FromTx(tx, &mpool));
- // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[0][5]
+ mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Height(blocknum).FromTx(tx));
+ // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
mpool.TrimToSize(1);
- BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[0][5]);
+ 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.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= feeEst.estimateFee(i).GetFeePerK());
+ BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
}
}
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index b6eb39bc38..3b79f8000d 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -11,76 +11,64 @@
#include <boost/test/unit_test.hpp>
-using namespace std;
-
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].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);
}
@@ -90,7 +78,7 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)
CBlockIndex *p2 = &blocks[GetRand(10000)];
CBlockIndex *p3 = &blocks[GetRand(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 d1407c1da9..cfed5e347e 100644
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -1,15 +1,15 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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 <vector>
#include "prevector.h"
-#include "random.h"
#include "serialize.h"
#include "streams.h"
#include "test/test_bitcoin.h"
+#include "test/test_random.h"
#include <boost/test/unit_test.hpp>
@@ -26,57 +26,70 @@ class prevector_tester {
pretype pre_vector_alt;
typedef typename pretype::size_type Size;
+ bool passed = true;
+ FastRandomContext rand_cache;
+ uint256 rand_seed;
+
+ template <typename A, typename B>
+ void local_check_equal(A a, B b)
+ {
+ local_check(a == b);
+ }
+ void local_check(bool b)
+ {
+ passed &= b;
+ }
void test() {
const pretype& const_pre_vector = pre_vector;
- BOOST_CHECK_EQUAL(real_vector.size(), pre_vector.size());
- BOOST_CHECK_EQUAL(real_vector.empty(), pre_vector.empty());
+ local_check_equal(real_vector.size(), pre_vector.size());
+ local_check_equal(real_vector.empty(), pre_vector.empty());
for (Size s = 0; s < real_vector.size(); s++) {
- BOOST_CHECK(real_vector[s] == pre_vector[s]);
- BOOST_CHECK(&(pre_vector[s]) == &(pre_vector.begin()[s]));
- BOOST_CHECK(&(pre_vector[s]) == &*(pre_vector.begin() + s));
- BOOST_CHECK(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
+ local_check(real_vector[s] == pre_vector[s]);
+ local_check(&(pre_vector[s]) == &(pre_vector.begin()[s]));
+ local_check(&(pre_vector[s]) == &*(pre_vector.begin() + s));
+ local_check(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
}
- // BOOST_CHECK(realtype(pre_vector) == real_vector);
- BOOST_CHECK(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
- BOOST_CHECK(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
+ // local_check(realtype(pre_vector) == real_vector);
+ 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) {
- BOOST_CHECK(v == real_vector[pos++]);
+ local_check(v == real_vector[pos++]);
}
BOOST_REVERSE_FOREACH(const T& v, pre_vector) {
- BOOST_CHECK(v == real_vector[--pos]);
+ local_check(v == real_vector[--pos]);
}
BOOST_FOREACH(const T& v, const_pre_vector) {
- BOOST_CHECK(v == real_vector[pos++]);
+ local_check(v == real_vector[pos++]);
}
BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) {
- BOOST_CHECK(v == real_vector[--pos]);
+ local_check(v == real_vector[--pos]);
}
CDataStream ss1(SER_DISK, 0);
CDataStream ss2(SER_DISK, 0);
ss1 << real_vector;
ss2 << pre_vector;
- BOOST_CHECK_EQUAL(ss1.size(), ss2.size());
+ local_check_equal(ss1.size(), ss2.size());
for (Size s = 0; s < ss1.size(); s++) {
- BOOST_CHECK_EQUAL(ss1[s], ss2[s]);
+ local_check_equal(ss1[s], ss2[s]);
}
}
public:
void resize(Size s) {
real_vector.resize(s);
- BOOST_CHECK_EQUAL(real_vector.size(), s);
+ local_check_equal(real_vector.size(), s);
pre_vector.resize(s);
- BOOST_CHECK_EQUAL(pre_vector.size(), s);
+ local_check_equal(pre_vector.size(), s);
test();
}
void reserve(Size s) {
real_vector.reserve(s);
- BOOST_CHECK(real_vector.capacity() >= s);
+ local_check(real_vector.capacity() >= s);
pre_vector.reserve(s);
- BOOST_CHECK(pre_vector.capacity() >= s);
+ local_check(pre_vector.capacity() >= s);
test();
}
@@ -157,6 +170,28 @@ public:
pre_vector.swap(pre_vector_alt);
test();
}
+
+ void move() {
+ real_vector = std::move(real_vector_alt);
+ real_vector_alt.clear();
+ pre_vector = std::move(pre_vector_alt);
+ pre_vector_alt.clear();
+ }
+
+ void copy() {
+ real_vector = real_vector_alt;
+ pre_vector = pre_vector_alt;
+ }
+
+ ~prevector_tester() {
+ BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString());
+ }
+
+ prevector_tester() {
+ seed_insecure_rand();
+ rand_seed = insecure_rand_seed;
+ rand_cache = insecure_rand_ctx;
+ }
};
BOOST_AUTO_TEST_CASE(PrevectorTestInt)
@@ -218,9 +253,15 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt)
if (((r >> 21) % 512) == 12) {
test.assign(insecure_rand() % 32, insecure_rand());
}
- if (((r >> 15) % 64) == 3) {
+ if (((r >> 15) % 8) == 3) {
test.swap();
}
+ if (((r >> 15) % 16) == 8) {
+ test.copy();
+ }
+ if (((r >> 15) % 32) == 18) {
+ test.move();
+ }
}
}
}
diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp
new file mode 100644
index 0000000000..0f40874f55
--- /dev/null
+++ b/src/test/raii_event_tests.cpp
@@ -0,0 +1,94 @@
+// Copyright (c) 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 <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>
+
+#include "support/events.h"
+
+#include "test/test_bitcoin.h"
+
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+static std::map<void*, short> tags;
+static std::map<void*, uint16_t> orders;
+static uint16_t tagSequence = 0;
+
+static void* tag_malloc(size_t sz) {
+ void* mem = malloc(sz);
+ if (!mem) return mem;
+ tags[mem]++;
+ orders[mem] = tagSequence++;
+ return mem;
+}
+
+static void tag_free(void* mem) {
+ tags[mem]--;
+ orders[mem] = tagSequence++;
+ free(mem);
+}
+
+BOOST_FIXTURE_TEST_SUITE(raii_event_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(raii_event_creation)
+{
+ event_set_mem_functions(tag_malloc, realloc, tag_free);
+
+ void* base_ptr = NULL;
+ {
+ auto base = obtain_event_base();
+ base_ptr = (void*)base.get();
+ BOOST_CHECK(tags[base_ptr] == 1);
+ }
+ BOOST_CHECK(tags[base_ptr] == 0);
+
+ void* event_ptr = NULL;
+ {
+ auto base = obtain_event_base();
+ auto event = obtain_event(base.get(), -1, 0, NULL, NULL);
+
+ base_ptr = (void*)base.get();
+ event_ptr = (void*)event.get();
+
+ BOOST_CHECK(tags[base_ptr] == 1);
+ BOOST_CHECK(tags[event_ptr] == 1);
+ }
+ BOOST_CHECK(tags[base_ptr] == 0);
+ BOOST_CHECK(tags[event_ptr] == 0);
+
+ event_set_mem_functions(malloc, realloc, free);
+}
+
+BOOST_AUTO_TEST_CASE(raii_event_order)
+{
+ event_set_mem_functions(tag_malloc, realloc, tag_free);
+
+ void* base_ptr = NULL;
+ void* event_ptr = NULL;
+ {
+ auto base = obtain_event_base();
+ auto event = obtain_event(base.get(), -1, 0, NULL, NULL);
+
+ base_ptr = (void*)base.get();
+ event_ptr = (void*)event.get();
+
+ // base should have allocated before event
+ BOOST_CHECK(orders[base_ptr] < orders[event_ptr]);
+ }
+ // base should be freed after event
+ BOOST_CHECK(orders[base_ptr] > orders[event_ptr]);
+
+ event_set_mem_functions(malloc, realloc, free);
+}
+
+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..8596734226
--- /dev/null
+++ b/src/test/random_tests.cpp
@@ -0,0 +1,53 @@
+// 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_EQUAL(ctx1.randbits(7), ctx2.randbits(7));
+ BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
+ BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
+
+ // Check that a nondeterministic ones are not
+ FastRandomContext ctx3;
+ FastRandomContext ctx4;
+ BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal
+}
+
+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/reverselock_tests.cpp b/src/test/reverselock_tests.cpp
index 8bdff97000..00dc47e13e 100644
--- a/src/test/reverselock_tests.cpp
+++ b/src/test/reverselock_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index bbda6a48f4..7cf2a744ea 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -16,35 +16,24 @@
#include <univalue.h>
-using namespace std;
-
-UniValue
-createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
-{
- UniValue result(UniValue::VARR);
- result.push_back(nRequired);
- UniValue addresses(UniValue::VARR);
- if (address1) addresses.push_back(address1);
- if (address2) addresses.push_back(address2);
- result.push_back(addresses);
- return result;
-}
-
-UniValue CallRPC(string args)
+UniValue CallRPC(std::string args)
{
- vector<string> vArgs;
+ std::vector<std::string> vArgs;
boost::split(vArgs, args, boost::is_any_of(" \t"));
- string strMethod = vArgs[0];
+ std::string strMethod = vArgs[0];
vArgs.erase(vArgs.begin());
- UniValue params = RPCConvertValues(strMethod, vArgs);
+ JSONRPCRequest request;
+ request.strMethod = strMethod;
+ request.params = RPCConvertValues(strMethod, vArgs);
+ request.fHelp = false;
BOOST_CHECK(tableRPC[strMethod]);
rpcfn_type method = tableRPC[strMethod]->actor;
try {
- UniValue result = (*method)(params, false);
+ UniValue result = (*method)(request);
return result;
}
catch (const UniValue& objError) {
- throw runtime_error(find_value(objError, "message").get_str());
+ throw std::runtime_error(find_value(objError, "message").get_str());
}
}
@@ -56,59 +45,81 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
// Test raw transaction API argument handling
UniValue r;
- BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), std::runtime_error);
- BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), std::runtime_error);
BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [] {}"));
- BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), std::runtime_error);
- BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error);
- string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
- BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx));
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), std::runtime_error);
+ std::string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx));
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 193);
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1);
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0);
- BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx+" extra"), runtime_error);
+ BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error);
- BOOST_CHECK_THROW(CallRPC("signrawtransaction"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx));
- BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY"));
- BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY"));
- BOOST_CHECK_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null badenum"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), std::runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC(std::string("signrawtransaction ")+rawtx));
+ BOOST_CHECK_NO_THROW(CallRPC(std::string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY"));
+ BOOST_CHECK_NO_THROW(CallRPC(std::string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY"));
+ BOOST_CHECK_THROW(CallRPC(std::string("signrawtransaction ")+rawtx+" null null badenum"), std::runtime_error);
// Only check failure cases for sendrawtransaction, there's no network to send to...
- BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), runtime_error);
- BOOST_CHECK_THROW(CallRPC(string("sendrawtransaction ")+rawtx+" extra"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC(std::string("sendrawtransaction ")+rawtx+" extra"), std::runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE(rpc_togglenetwork)
+{
+ UniValue r;
+
+ r = CallRPC("getnetworkinfo");
+ bool netState = find_value(r.get_obj(), "networkactive").get_bool();
+ BOOST_CHECK_EQUAL(netState, true);
+
+ BOOST_CHECK_NO_THROW(CallRPC("setnetworkactive false"));
+ r = CallRPC("getnetworkinfo");
+ int numConnection = find_value(r.get_obj(), "connections").get_int();
+ BOOST_CHECK_EQUAL(numConnection, 0);
+
+ netState = find_value(r.get_obj(), "networkactive").get_bool();
+ BOOST_CHECK_EQUAL(netState, false);
+
+ BOOST_CHECK_NO_THROW(CallRPC("setnetworkactive true"));
+ r = CallRPC("getnetworkinfo");
+ netState = find_value(r.get_obj(), "networkactive").get_bool();
+ BOOST_CHECK_EQUAL(netState, true);
}
BOOST_AUTO_TEST_CASE(rpc_rawsign)
{
UniValue r;
// input is a 1-of-2 multisig (so is output):
- string prevout =
+ std::string prevout =
"[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\","
"\"vout\":1,\"scriptPubKey\":\"a914b10c9df5f7edf436c697f02f1efdba4cf399615187\","
"\"redeemScript\":\"512103debedc17b3df2badbcdd86d5feb4562b86fe182e5998abd8bcd4f122c6155b1b21027e940bb73ab8732bfdf7f9216ecefca5b94d6df834e77e108f68e66f126044c052ae\"}]";
- r = CallRPC(string("createrawtransaction ")+prevout+" "+
+ r = CallRPC(std::string("createrawtransaction ")+prevout+" "+
"{\"3HqAe9LtNBjnsfM4CyYaWTnvCaUYT7v4oZ\":11}");
- string notsigned = r.get_str();
- string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\"";
- string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\"";
- r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]");
+ std::string notsigned = r.get_str();
+ std::string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\"";
+ std::string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\"";
+ r = CallRPC(std::string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]");
BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false);
- r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]");
+ r = CallRPC(std::string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]");
BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true);
}
@@ -120,11 +131,11 @@ BOOST_AUTO_TEST_CASE(rpc_createraw_op_return)
BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\",\"data\":\"68656c6c6f776f726c64\"}"));
// Key not "data" (bad address)
- BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), std::runtime_error);
// Bad hex encoding of data output
- BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345\"}"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345g\"}"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345\"}"), std::runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345g\"}"), std::runtime_error);
// Data 81 bytes long
BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081\"}"));
@@ -228,23 +239,23 @@ BOOST_AUTO_TEST_CASE(json_parse_errors)
BOOST_AUTO_TEST_CASE(rpc_ban)
{
- BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
-
+ BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
+
UniValue r;
- BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0 add")));
- BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.0:8334")), runtime_error); //portnumber for setban not allowed
- BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0 add")));
+ BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.0.0:8334")), std::runtime_error); //portnumber for setban not allowed
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
UniValue ar = r.get_array();
UniValue o1 = ar[0].get_obj();
UniValue adr = find_value(o1, "address");
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/32");
- BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0 remove")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0 remove")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
BOOST_CHECK_EQUAL(ar.size(), 0);
- BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 1607731200 true")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 1607731200 true")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
adr = find_value(o1, "address");
@@ -252,10 +263,10 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check
- BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+ BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 200")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 200")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
adr = find_value(o1, "address");
@@ -265,44 +276,44 @@ 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
- BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.1 add")), runtime_error);
+ // 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(string("setban 127.0.0.0/24 remove")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0/24 remove")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
BOOST_CHECK_EQUAL(ar.size(), 0);
- BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/255.255.0.0 add")));
- BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.1.1 add")), runtime_error);
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/255.255.0.0 add")));
+ BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.1.1 add")), std::runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
BOOST_CHECK_EQUAL(ar.size(), 0);
- BOOST_CHECK_THROW(r = CallRPC(string("setban test add")), runtime_error); //invalid IP
+ BOOST_CHECK_THROW(r = CallRPC(std::string("setban test add")), std::runtime_error); //invalid IP
//IPv6 tests
- BOOST_CHECK_NO_THROW(r = CallRPC(string("setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
adr = find_value(o1, "address");
BOOST_CHECK_EQUAL(adr.get_str(), "fe80::202:b3ff:fe1e:8329/128");
- BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:db8::/ffff:fffc:0:0:0:0:0:0 add")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 2001:db8::/ffff:fffc:0:0:0:0:0:0 add")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
adr = find_value(o1, "address");
BOOST_CHECK_EQUAL(adr.get_str(), "2001:db8::/30");
- BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add")));
- BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
adr = find_value(o1, "address");
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index aa12dfbd54..e4ddf9d618 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -42,15 +42,13 @@ static void MicroSleep(uint64_t n)
BOOST_AUTO_TEST_CASE(manythreads)
{
- seed_insecure_rand(false);
-
// Stress test: hundreds of microsecond-scheduled tasks,
// serviced by 10 threads.
//
// So... ten shared counters, which if all the tasks execute
// properly will sum to the number of tasks done.
- // Each task adds or subtracts from one of the counters a
- // random amount, and then schedules another task 0-1000
+ // 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.
@@ -58,7 +56,7 @@ BOOST_AUTO_TEST_CASE(manythreads)
boost::mutex counterMutex[10];
int counter[10] = { 0 };
- boost::random::mt19937 rng(insecure_rand());
+ 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);
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 5224b57ca4..f8fd8cc30c 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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 "core_io.h"
#include "key.h"
#include "keystore.h"
-#include "main.h"
+#include "validation.h"
#include "policy/policy.h"
#include "script/script.h"
#include "script/script_error.h"
@@ -17,8 +17,6 @@
#include <boost/test/unit_test.hpp>
-using namespace std;
-
// Helpers:
static std::vector<unsigned char>
Serialize(const CScript& s)
@@ -80,7 +78,7 @@ BOOST_AUTO_TEST_CASE(sign)
}
CMutableTransaction txFrom; // Funding transaction:
- string reason;
+ std::string reason;
txFrom.vout.resize(8);
for (int i = 0; i < 4; i++)
{
@@ -107,18 +105,20 @@ BOOST_AUTO_TEST_CASE(sign)
}
// All of the above should be OK, and the txTos have valid signatures
// Check to make sure signature verification fails if we use the wrong ScriptSig:
- for (int i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++) {
+ PrecomputedTransactionData txdata(txTo[i]);
for (int j = 0; j < 8; j++)
{
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)();
+ bool sigOK = CScriptCheck(CCoins(txFrom, 0), 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
BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
txTo[i].vin[0].scriptSig = sigSave;
}
+ }
}
BOOST_AUTO_TEST_CASE(norecurse)
@@ -176,7 +176,7 @@ BOOST_AUTO_TEST_CASE(set)
}
CMutableTransaction txFrom; // Funding transaction:
- string reason;
+ std::string reason;
txFrom.vout.resize(4);
for (int i = 0; i < 4; i++)
{
@@ -261,7 +261,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
CCoinsViewCache coins(&coinsDummy);
CBasicKeyStore keystore;
CKey key[6];
- vector<CPubKey> keys;
+ std::vector<CPubKey> keys;
for (int i = 0; i < 6; i++)
{
key[i].MakeNewKey(true);
@@ -333,8 +333,8 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
// SignSignature doesn't know how to sign these. We're
// not testing validating signatures, so just create
// dummy signatures that DO include the correct P2SH scripts:
- txTo.vin[3].scriptSig << OP_11 << OP_11 << vector<unsigned char>(oneAndTwo.begin(), oneAndTwo.end());
- txTo.vin[4].scriptSig << vector<unsigned char>(fifteenSigops.begin(), fifteenSigops.end());
+ txTo.vin[3].scriptSig << OP_11 << OP_11 << std::vector<unsigned char>(oneAndTwo.begin(), oneAndTwo.end());
+ txTo.vin[4].scriptSig << std::vector<unsigned char>(fifteenSigops.begin(), fifteenSigops.end());
BOOST_CHECK(::AreInputsStandard(txTo, coins));
// 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
@@ -347,7 +347,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd1.vin.resize(1);
txToNonStd1.vin[0].prevout.n = 5;
txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
- txToNonStd1.vin[0].scriptSig << vector<unsigned char>(sixteenSigops.begin(), sixteenSigops.end());
+ txToNonStd1.vin[0].scriptSig << std::vector<unsigned char>(sixteenSigops.begin(), sixteenSigops.end());
BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins));
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U);
@@ -359,7 +359,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd2.vin.resize(1);
txToNonStd2.vin[0].prevout.n = 6;
txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
- txToNonStd2.vin[0].scriptSig << vector<unsigned char>(twentySigops.begin(), twentySigops.end());
+ txToNonStd2.vin[0].scriptSig << std::vector<unsigned char>(twentySigops.begin(), twentySigops.end());
BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins));
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U);
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 5a9aaf9bc0..343c645cb1 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -29,15 +29,13 @@
#include <univalue.h>
-using namespace std;
-
// 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(string strFlags);
-string FormatScriptFlags(unsigned int flags);
+unsigned int ParseScriptFlags(std::string strFlags);
+std::string FormatScriptFlags(unsigned int flags);
UniValue
read_json(const std::string& jsondata)
@@ -89,6 +87,8 @@ static ScriptErrorDesc script_errors[]={
{SCRIPT_ERR_SIG_NULLDUMMY, "SIG_NULLDUMMY"},
{SCRIPT_ERR_PUBKEYTYPE, "PUBKEYTYPE"},
{SCRIPT_ERR_CLEANSTACK, "CLEANSTACK"},
+ {SCRIPT_ERR_MINIMALIF, "MINIMALIF"},
+ {SCRIPT_ERR_SIG_NULLFAIL, "NULLFAIL"},
{SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "DISCOURAGE_UPGRADABLE_NOPS"},
{SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"},
{SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH, "WITNESS_PROGRAM_WRONG_LENGTH"},
@@ -97,6 +97,7 @@ static ScriptErrorDesc script_errors[]={
{SCRIPT_ERR_WITNESS_MALLEATED, "WITNESS_MALLEATED"},
{SCRIPT_ERR_WITNESS_MALLEATED_P2SH, "WITNESS_MALLEATED_P2SH"},
{SCRIPT_ERR_WITNESS_UNEXPECTED, "WITNESS_UNEXPECTED"},
+ {SCRIPT_ERR_WITNESS_PUBKEYTYPE, "WITNESS_PUBKEYTYPE"},
};
const char *FormatScriptError(ScriptError_t err)
@@ -142,8 +143,7 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CSc
txSpend.nLockTime = 0;
txSpend.vin.resize(1);
txSpend.vout.resize(1);
- txSpend.wit.vtxinwit.resize(1);
- txSpend.wit.vtxinwit[0].scriptWitness = scriptWitness;
+ txSpend.vin[0].scriptWitness = scriptWitness;
txSpend.vin[0].prevout.hash = txCredit.GetHash();
txSpend.vin[0].prevout.n = 0;
txSpend.vin[0].scriptSig = scriptSig;
@@ -170,11 +170,14 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
#if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << tx2;
- if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect, message);
- } else {
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect, message);
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(begin_ptr(scriptPubKey), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect,message);
+ 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);
+ } 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);
+ }
}
#endif
}
@@ -270,7 +273,7 @@ private:
//! The Witness embedded script
CScript witscript;
CScriptWitness scriptWitness;
- CTransaction creditTx;
+ CTransactionRef creditTx;
CMutableTransaction spendTx;
bool havePush;
std::vector<unsigned char> push;
@@ -313,8 +316,8 @@ public:
redeemscript = scriptPubKey;
scriptPubKey = CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemscript)) << OP_EQUAL;
}
- creditTx = BuildCreditingTransaction(scriptPubKey, nValue);
- spendTx = BuildSpendingTransaction(CScript(), CScriptWitness(), creditTx);
+ creditTx = MakeTransactionRef(BuildCreditingTransaction(scriptPubKey, nValue));
+ spendTx = BuildSpendingTransaction(CScript(), CScriptWitness(), *creditTx);
}
TestBuilder& ScriptError(ScriptError_t err)
@@ -323,10 +326,10 @@ public:
return *this;
}
- TestBuilder& Add(const CScript& script)
+ TestBuilder& Add(const CScript& _script)
{
DoPush();
- spendTx.vin[0].scriptSig += script;
+ spendTx.vin[0].scriptSig += _script;
return *this;
}
@@ -343,8 +346,8 @@ public:
return *this;
}
- TestBuilder& Push(const CScript& script) {
- DoPush(std::vector<unsigned char>(script.begin(), script.end()));
+ TestBuilder& Push(const CScript& _script) {
+ DoPush(std::vector<unsigned char>(_script.begin(), _script.end()));
return *this;
}
@@ -415,7 +418,7 @@ public:
{
TestBuilder copy = *this; // Make a copy so we can rollback the push.
DoPush();
- DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, scriptWitness, flags, comment, scriptError, nValue);
+ DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, scriptWitness, flags, comment, scriptError, nValue);
*this = copy;
return *this;
}
@@ -441,7 +444,7 @@ public:
array.push_back(wit);
}
array.push_back(FormatScript(spendTx.vin[0].scriptSig));
- array.push_back(FormatScript(creditTx.vout[0].scriptPubKey));
+ array.push_back(FormatScript(creditTx->vout[0].scriptPubKey));
array.push_back(FormatScriptFlags(flags));
array.push_back(FormatScriptError((ScriptError_t)scriptError));
array.push_back(comment);
@@ -452,17 +455,12 @@ public:
{
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");
@@ -795,7 +793,7 @@ BOOST_AUTO_TEST_CASE(script_build)
CScript witscript = CScript() << ToByteVector(keys.pubkey0);
uint256 hash;
CSHA256().Write(&witscript[0], witscript.size()).Finalize(hash.begin());
- vector<unsigned char> hashBytes = ToByteVector(hash);
+ std::vector<unsigned char> hashBytes = ToByteVector(hash);
hashBytes.pop_back();
tests.push_back(TestBuilder(CScript() << OP_0 << hashBytes,
"P2WPKH with wrong witness program length", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false
@@ -823,6 +821,99 @@ BOOST_AUTO_TEST_CASE(script_build)
"P2PK with witness", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH
).PushSig(keys.key0).Push("0").AsWit().ScriptError(SCRIPT_ERR_WITNESS_UNEXPECTED));
+ // Compressed keys should pass SCRIPT_VERIFY_WITNESS_PUBKEYTYPE
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
+ "Basic P2WSH with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).PushWitSig(keys.key0C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C),
+ "Basic P2WPKH with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_PKH,
+ 0, 1).PushWitSig(keys.key0C).Push(keys.pubkey0C).AsWit());
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
+ "Basic P2SH(P2WSH) with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).PushWitSig(keys.key0C).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C),
+ "Basic P2SH(P2WPKH) with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_PKH,
+ 0, 1).PushWitSig(keys.key0C).Push(keys.pubkey0C).AsWit().PushRedeem());
+
+ // Testing uncompressed key in witness with SCRIPT_VERIFY_WITNESS_PUBKEYTYPE
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
+ "Basic P2WSH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).PushWitSig(keys.key0).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0),
+ "Basic P2WPKH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_PKH,
+ 0, 1).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
+ "Basic P2SH(P2WSH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).PushWitSig(keys.key0).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0),
+ "Basic P2SH(P2WPKH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_PKH,
+ 0, 1).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+
+ // P2WSH 1-of-2 multisig with compressed keys
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().PushRedeem());
+
+ // P2WSH 1-of-2 multisig with first key uncompressed
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ // P2WSH 1-of-2 multisig with second key uncompressed
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG second key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+
std::set<std::string> tests_set;
{
@@ -867,7 +958,7 @@ BOOST_AUTO_TEST_CASE(script_json_test)
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
- string strTest = test.write();
+ std::string strTest = test.write();
CScriptWitness witness;
CAmount nValue = 0;
unsigned int pos = 0;
@@ -886,9 +977,9 @@ BOOST_AUTO_TEST_CASE(script_json_test)
}
continue;
}
- string scriptSigString = test[pos++].get_str();
+ std::string scriptSigString = test[pos++].get_str();
CScript scriptSig = ParseScript(scriptSigString);
- string scriptPubKeyString = test[pos++].get_str();
+ std::string scriptPubKeyString = test[pos++].get_str();
CScript scriptPubKey = ParseScript(scriptPubKeyString);
unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str());
int scriptError = ParseScriptError(test[pos++].get_str());
@@ -907,21 +998,21 @@ BOOST_AUTO_TEST_CASE(script_PushData)
static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a };
ScriptError err;
- vector<vector<unsigned char> > directStack;
+ std::vector<std::vector<unsigned char> > directStack;
BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
- vector<vector<unsigned char> > pushdata1Stack;
+ std::vector<std::vector<unsigned char> > pushdata1Stack;
BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err));
BOOST_CHECK(pushdata1Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
- vector<vector<unsigned char> > pushdata2Stack;
+ std::vector<std::vector<unsigned char> > pushdata2Stack;
BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err));
BOOST_CHECK(pushdata2Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
- vector<vector<unsigned char> > pushdata4Stack;
+ std::vector<std::vector<unsigned char> > pushdata4Stack;
BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err));
BOOST_CHECK(pushdata4Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
@@ -944,7 +1035,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
result << OP_0;
BOOST_FOREACH(const CKey &key, keys)
{
- vector<unsigned char> vchSig;
+ std::vector<unsigned char> vchSig;
BOOST_CHECK(key.Sign(hash, vchSig));
vchSig.push_back((unsigned char)SIGHASH_ALL);
result << vchSig;
@@ -974,18 +1065,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, NULL, 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, NULL, 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, NULL, 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, NULL, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
@@ -1007,54 +1098,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, NULL, 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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, NULL, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
}
@@ -1063,8 +1154,8 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
// Test the CombineSignatures function
CAmount amount = 0;
CBasicKeyStore keystore;
- vector<CKey> keys;
- vector<CPubKey> pubkeys;
+ std::vector<CKey> keys;
+ std::vector<CPubKey> pubkeys;
for (int i = 0; i < 3; i++)
{
CKey key;
@@ -1125,15 +1216,15 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
BOOST_CHECK(combined.scriptSig == scriptSig);
// A couple of partially-signed versions:
- vector<unsigned char> sig1;
+ std::vector<unsigned char> sig1;
uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);
BOOST_CHECK(keys[0].Sign(hash1, sig1));
sig1.push_back(SIGHASH_ALL);
- vector<unsigned char> sig2;
+ std::vector<unsigned char> sig2;
uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SIGVERSION_BASE);
BOOST_CHECK(keys[1].Sign(hash2, sig2));
sig2.push_back(SIGHASH_NONE);
- vector<unsigned char> sig3;
+ std::vector<unsigned char> sig3;
uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SIGVERSION_BASE);
BOOST_CHECK(keys[2].Sign(hash3, sig3));
sig3.push_back(SIGHASH_SINGLE);
@@ -1207,9 +1298,9 @@ BOOST_AUTO_TEST_CASE(script_GetScriptAsm)
BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2));
BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY));
- string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090");
- string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2");
- vector<unsigned char> vchPubKey = ToByteVector(ParseHex(pubKey));
+ std::string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090");
+ std::string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2");
+ std::vector<unsigned char> vchPubKey = ToByteVector(ParseHex(pubKey));
BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey, true));
BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey, true));
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index 6b6689c7d3..1d5893bdc3 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)
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index bec2c7459d..9661a66514 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -11,10 +11,52 @@
#include <boost/test/unit_test.hpp>
-using namespace std;
-
BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup)
+class CSerializeMethodsTestSingle
+{
+protected:
+ int intval;
+ bool boolval;
+ std::string stringval;
+ const char* charstrval;
+ CTransactionRef txval;
+public:
+ CSerializeMethodsTestSingle() = default;
+ CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), charstrval(charstrvalin), txval(MakeTransactionRef(txvalin)){}
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(intval);
+ READWRITE(boolval);
+ READWRITE(stringval);
+ READWRITE(FLATDATA(charstrval));
+ READWRITE(txval);
+ }
+
+ bool operator==(const CSerializeMethodsTestSingle& rhs)
+ {
+ return intval == rhs.intval && \
+ boolval == rhs.boolval && \
+ stringval == rhs.stringval && \
+ strcmp(charstrval, rhs.charstrval) == 0 && \
+ *txval == *rhs.txval;
+ }
+};
+
+class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle
+{
+public:
+ using CSerializeMethodsTestSingle::CSerializeMethodsTestSingle;
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITEMANY(intval, boolval, stringval, FLATDATA(charstrval), txval);
+ }
+};
+
BOOST_AUTO_TEST_CASE(sizes)
{
BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(char(0), 0));
@@ -48,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);
@@ -67,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);
@@ -184,7 +226,7 @@ BOOST_AUTO_TEST_CASE(varints_bitpatterns)
BOOST_AUTO_TEST_CASE(compactsize)
{
CDataStream ss(SER_DISK, 0);
- vector<char>::size_type i, j;
+ std::vector<char>::size_type i, j;
for (i = 1; i <= MAX_SIZE; i *= 2)
{
@@ -217,7 +259,7 @@ BOOST_AUTO_TEST_CASE(noncanonical)
// Write some non-canonical CompactSize encodings, and
// make sure an exception is thrown when read back.
CDataStream ss(SER_DISK, 0);
- vector<char>::size_type n;
+ std::vector<char>::size_type n;
// zero encoded with three bytes:
ss.write("\xfd\x00\x00", 3);
@@ -297,4 +339,30 @@ BOOST_AUTO_TEST_CASE(insert_delete)
BOOST_CHECK_EQUAL(ss.size(), 0);
}
+BOOST_AUTO_TEST_CASE(class_methods)
+{
+ int intval(100);
+ bool boolval(true);
+ std::string stringval("testing");
+ const char* charstrval("testing charstr");
+ CMutableTransaction txval;
+ CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, txval);
+ CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, txval);
+ CSerializeMethodsTestSingle methodtest3;
+ CSerializeMethodsTestMany methodtest4;
+ CDataStream ss(SER_DISK, PROTOCOL_VERSION);
+ BOOST_CHECK(methodtest1 == methodtest2);
+ ss << methodtest1;
+ ss >> methodtest4;
+ ss << methodtest2;
+ ss >> methodtest3;
+ BOOST_CHECK(methodtest1 == methodtest2);
+ BOOST_CHECK(methodtest2 == methodtest3);
+ BOOST_CHECK(methodtest3 == methodtest4);
+
+ CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, FLATDATA(charstrval), txval);
+ ss2 >> methodtest3;
+ BOOST_CHECK(methodtest3 == methodtest4);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 4a48347b70..5279cb243b 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -1,17 +1,17 @@
-// Copyright (c) 2013-2015 The Bitcoin Core developers
+// Copyright (c) 2013-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 "consensus/validation.h"
#include "data/sighash.json.h"
#include "hash.h"
-#include "main.h" // For CheckTransaction
-#include "random.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"
@@ -184,7 +184,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
std::string raw_tx, raw_script, sigHashHex;
int nIn, nHashType;
uint256 sh;
- CTransaction tx;
+ CTransactionRef tx;
CScript scriptCode = CScript();
try {
@@ -199,7 +199,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
stream >> tx;
CValidationState state;
- BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
+ BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest);
BOOST_CHECK(state.IsValid());
std::vector<unsigned char> raw = ParseHex(raw_script);
@@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
continue;
}
- sh = SignatureHash(scriptCode, tx, nIn, nHashType, 0, SIGVERSION_BASE);
+ sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, SIGVERSION_BASE);
BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest);
}
}
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index e8a63ae60c..13d8911f03 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -1,8 +1,8 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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 "main.h"
+#include "validation.h"
#include "pubkey.h"
#include "key.h"
#include "script/script.h"
@@ -15,8 +15,6 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-using namespace std;
-
// Helpers:
static std::vector<unsigned char>
Serialize(const CScript& s)
@@ -73,7 +71,7 @@ ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction
{
ScriptError error;
CTransaction inputi(input);
- bool ret = VerifyScript(inputi.vin[0].scriptSig, output.vout[0].scriptPubKey, inputi.wit.vtxinwit.size() > 0 ? &inputi.wit.vtxinwit[0].scriptWitness : NULL, flags, TransactionSignatureChecker(&inputi, 0, output.vout[0].nValue), &error);
+ bool ret = VerifyScript(inputi.vin[0].scriptSig, output.vout[0].scriptPubKey, &inputi.vin[0].scriptWitness, flags, TransactionSignatureChecker(&inputi, 0, output.vout[0].nValue), &error);
BOOST_CHECK((ret == true) == (error == SCRIPT_ERR_OK));
return error;
@@ -84,13 +82,12 @@ ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction
* and witness such that spendingTx spends output zero of creationTx.
* Also inserts creationTx's output into the coins view.
*/
-void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CTxInWitness& witness)
+void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& witness)
{
creationTx.nVersion = 1;
creationTx.vin.resize(1);
creationTx.vin[0].prevout.SetNull();
creationTx.vin[0].scriptSig = CScript();
- creationTx.wit.vtxinwit.resize(1);
creationTx.vout.resize(1);
creationTx.vout[0].nValue = 1;
creationTx.vout[0].scriptPubKey = scriptPubKey;
@@ -100,8 +97,7 @@ void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableT
spendingTx.vin[0].prevout.hash = creationTx.GetHash();
spendingTx.vin[0].prevout.n = 0;
spendingTx.vin[0].scriptSig = scriptSig;
- spendingTx.wit.vtxinwit.resize(1);
- spendingTx.wit.vtxinwit[0] = witness;
+ spendingTx.vin[0].scriptWitness = witness;
spendingTx.vout.resize(1);
spendingTx.vout[0].nValue = 1;
spendingTx.vout[0].scriptPubKey = CScript();
@@ -133,7 +129,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
// Do not use a valid signature to avoid using wallet operations.
CScript scriptSig = CScript() << OP_0 << OP_0;
- BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CTxInWitness());
+ BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CScriptWitness());
// Legacy counting only includes signature operations in scriptSigs and scriptPubKeys
// of a transaction and does not take the actual executed sig operations into account.
// spendingTx in itself does not contain a signature operation.
@@ -151,7 +147,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
CScript scriptSig = CScript() << OP_0 << OP_0 << ToByteVector(redeemScript);
- BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CTxInWitness());
+ BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CScriptWitness());
assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 2 * WITNESS_SCALE_FACTOR);
assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);
}
@@ -161,14 +157,12 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
CScript p2pk = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
CScript scriptPubKey = GetScriptForWitness(p2pk);
CScript scriptSig = CScript();
- CTxInWitness witness;
CScriptWitness scriptWitness;
- scriptWitness.stack.push_back(vector<unsigned char>(0));
- scriptWitness.stack.push_back(vector<unsigned char>(0));
- witness.scriptWitness = scriptWitness;
+ scriptWitness.stack.push_back(std::vector<unsigned char>(0));
+ scriptWitness.stack.push_back(std::vector<unsigned char>(0));
- BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, witness);
+ BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 1);
// No signature operations if we don't verify the witness.
assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags & ~SCRIPT_VERIFY_WITNESS) == 0);
@@ -177,10 +171,10 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
// The sig op cost for witness version != 0 is zero.
assert(scriptPubKey[0] == 0x00);
scriptPubKey[0] = 0x51;
- BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, witness);
+ BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 0);
scriptPubKey[0] = 0x00;
- BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, witness);
+ BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
// The witness of a coinbase transaction is not taken into account.
spendingTx.vin[0].prevout.SetNull();
@@ -193,13 +187,11 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
CScript scriptSig = GetScriptForWitness(p2pk);
CScript scriptPubKey = GetScriptForDestination(CScriptID(scriptSig));
scriptSig = CScript() << ToByteVector(scriptSig);
- CTxInWitness witness;
CScriptWitness scriptWitness;
- scriptWitness.stack.push_back(vector<unsigned char>(0));
- scriptWitness.stack.push_back(vector<unsigned char>(0));
- witness.scriptWitness = scriptWitness;
+ scriptWitness.stack.push_back(std::vector<unsigned char>(0));
+ scriptWitness.stack.push_back(std::vector<unsigned char>(0));
- BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, witness);
+ BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 1);
assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_EQUALVERIFY);
}
@@ -209,14 +201,12 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
CScript witnessScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;
CScript scriptPubKey = GetScriptForWitness(witnessScript);
CScript scriptSig = CScript();
- CTxInWitness witness;
CScriptWitness scriptWitness;
- scriptWitness.stack.push_back(vector<unsigned char>(0));
- scriptWitness.stack.push_back(vector<unsigned char>(0));
- scriptWitness.stack.push_back(vector<unsigned char>(witnessScript.begin(), witnessScript.end()));
- witness.scriptWitness = scriptWitness;
+ scriptWitness.stack.push_back(std::vector<unsigned char>(0));
+ scriptWitness.stack.push_back(std::vector<unsigned char>(0));
+ scriptWitness.stack.push_back(std::vector<unsigned char>(witnessScript.begin(), witnessScript.end()));
- BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, witness);
+ BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 2);
assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags & ~SCRIPT_VERIFY_WITNESS) == 0);
assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);
@@ -228,14 +218,12 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
CScript redeemScript = GetScriptForWitness(witnessScript);
CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
CScript scriptSig = CScript() << ToByteVector(redeemScript);
- CTxInWitness witness;
CScriptWitness scriptWitness;
- scriptWitness.stack.push_back(vector<unsigned char>(0));
- scriptWitness.stack.push_back(vector<unsigned char>(0));
- scriptWitness.stack.push_back(vector<unsigned char>(witnessScript.begin(), witnessScript.end()));
- witness.scriptWitness = scriptWitness;
+ scriptWitness.stack.push_back(std::vector<unsigned char>(0));
+ scriptWitness.stack.push_back(std::vector<unsigned char>(0));
+ scriptWitness.stack.push_back(std::vector<unsigned char>(witnessScript.begin(), witnessScript.end()));
- BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, witness);
+ BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 2);
assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);
}
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index f14b902fe1..0b2fe0ef9d 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Copyright (c) 2014-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 "chain.h"
-#include "random.h"
#include "util.h"
#include "test/test_bitcoin.h"
+#include "test/test_random.h"
#include <vector>
@@ -100,4 +100,47 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
}
}
+BOOST_AUTO_TEST_CASE(findearliestatleast_test)
+{
+ std::vector<uint256> vHashMain(100000);
+ std::vector<CBlockIndex> vBlocksMain(100000);
+ 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].phashBlock = &vHashMain[i];
+ vBlocksMain[i].BuildSkip();
+ if (i < 10) {
+ vBlocksMain[i].nTime = i;
+ vBlocksMain[i].nTimeMax = i;
+ } else {
+ // randomly choose something in the range [MTP, MTP*2]
+ int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast();
+ int r = insecure_rand() % medianTimePast;
+ vBlocksMain[i].nTime = r + medianTimePast;
+ vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i-1].nTimeMax);
+ }
+ }
+ // Check that we set nTimeMax up correctly.
+ unsigned int curTimeMax = 0;
+ for (unsigned int i=0; i<vBlocksMain.size(); ++i) {
+ curTimeMax = std::max(curTimeMax, vBlocksMain[i].nTime);
+ BOOST_CHECK(curTimeMax == vBlocksMain[i].nTimeMax);
+ }
+
+ // Build a CChain for the main branch.
+ CChain chain;
+ chain.SetTip(&vBlocksMain.back());
+
+ // 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();
+ 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(vBlocksMain[r].GetAncestor(ret->nHeight) == ret);
+ }
+}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 34f501e867..94b5cc119b 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -9,12 +9,69 @@
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/assert.hpp>
#include <boost/test/unit_test.hpp>
-
-using namespace std;
+
using namespace boost::assign; // bring 'operator+=()' into scope
BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)
+BOOST_AUTO_TEST_CASE(streams_vector_writer)
+{
+ unsigned char a(1);
+ unsigned char b(2);
+ unsigned char bytes[] = { 3, 4, 5, 6 };
+ std::vector<unsigned char> vch;
+
+ // Each test runs twice. Serializing a second time at the same starting
+ // point should yield the same results, even if the first test grew the
+ // vector.
+
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));
+ vch.clear();
+
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));
+ vch.clear();
+
+ vch.resize(5, 0);
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));
+ vch.clear();
+
+ vch.resize(4, 0);
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));
+ vch.clear();
+
+ vch.resize(4, 0);
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));
+ vch.clear();
+
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
+ BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));
+ BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));
+ vch.clear();
+
+ vch.resize(4, 8);
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
+ CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);
+ BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));
+ vch.clear();
+}
+
BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
{
std::vector<char> in;
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 856f9b8423..cb625bda11 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -1,17 +1,17 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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 "test_bitcoin.h"
#include "chainparams.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
+#include "fs.h"
#include "key.h"
-#include "main.h"
+#include "validation.h"
#include "miner.h"
+#include "net_processing.h"
#include "pubkey.h"
#include "random.h"
#include "txdb.h"
@@ -19,13 +19,17 @@
#include "ui_interface.h"
#include "rpc/server.h"
#include "rpc/register.h"
+#include "script/sigcache.h"
#include "test/testutil.h"
-#include <boost/filesystem.hpp>
-#include <boost/test/unit_test.hpp>
+#include <memory>
+
#include <boost/thread.hpp>
+uint256 insecure_rand_seed = GetRandHash();
+FastRandomContext insecure_rand_ctx(insecure_rand_seed);
+
extern bool fPrintToConsole;
extern void noui_connect();
@@ -34,6 +38,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
ECC_Start();
SetupEnvironment();
SetupNetworking();
+ InitSignatureCache();
fPrintToDebugLog = false; // don't want to write to debug.log file
fCheckBlockIndex = true;
SelectParams(chainName);
@@ -43,6 +48,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
BasicTestingSetup::~BasicTestingSetup()
{
ECC_Stop();
+ g_connman.reset();
}
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
@@ -50,19 +56,30 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
const CChainParams& chainparams = Params();
// Ideally we'd move all the RPC tests to the functional testing framework
// instead of unit tests, but for now we need these here.
+
RegisterAllCoreRPCCommands(tableRPC);
ClearDatadirCache();
pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
- boost::filesystem::create_directories(pathTemp);
- mapArgs["-datadir"] = pathTemp.string();
+ fs::create_directories(pathTemp);
+ ForceSetArg("-datadir", pathTemp.string());
mempool.setSanityCheck(1.0);
pblocktree = new CBlockTreeDB(1 << 20, true);
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
- InitBlockIndex(chainparams);
+ if (!InitBlockIndex(chainparams)) {
+ throw std::runtime_error("InitBlockIndex failed.");
+ }
+ {
+ CValidationState state;
+ 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());
}
@@ -75,7 +92,7 @@ TestingSetup::~TestingSetup()
delete pcoinsTip;
delete pcoinsdbview;
delete pblocktree;
- boost::filesystem::remove_all(pathTemp);
+ fs::remove_all(pathTemp);
}
TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
@@ -87,7 +104,7 @@ TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
{
std::vector<CMutableTransaction> noTxns;
CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
- coinbaseTxns.push_back(b.vtx[0]);
+ coinbaseTxns.push_back(*b.vtx[0]);
}
}
@@ -99,24 +116,23 @@ CBlock
TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
{
const CChainParams& chainparams = Params();
- CBlockTemplate *pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
+ std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
CBlock& block = pblocktemplate->block;
// Replace mempool-selected txns with just coinbase plus passed-in txns:
block.vtx.resize(1);
BOOST_FOREACH(const CMutableTransaction& tx, txns)
- block.vtx.push_back(tx);
+ block.vtx.push_back(MakeTransactionRef(tx));
// IncrementExtraNonce creates a valid coinbase and merkleRoot
unsigned int extraNonce = 0;
IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
- CValidationState state;
- ProcessNewBlock(state, chainparams, NULL, &block, true, NULL);
+ std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
+ ProcessNewBlock(chainparams, shared_pblock, true, NULL);
CBlock result = block;
- delete pblocktemplate;
return result;
}
@@ -125,31 +141,12 @@ TestChain100Setup::~TestChain100Setup()
}
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) {
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
CTransaction txn(tx);
- return FromTx(txn, pool);
-}
-
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CTransaction &txn, CTxMemPool *pool) {
- bool hasNoDependencies = pool ? pool->HasNoInputsOf(txn) : hadNoDependencies;
- // Hack to assume either its completely dependent on other mempool txs or not at all
- CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0;
-
- return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight,
- hasNoDependencies, inChainValue, spendsCoinbase, sigOpCost, lp);
+ return FromTx(txn);
}
-void Shutdown(void* parg)
-{
- exit(0);
-}
-
-void StartShutdown()
-{
- exit(0);
-}
-
-bool ShutdownRequested()
-{
- return false;
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) {
+ return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,
+ spendsCoinbase, sigOpCost, lp);
}
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index bc0d2fe316..60a86d8c48 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -6,12 +6,12 @@
#define BITCOIN_TEST_TEST_BITCOIN_H
#include "chainparamsbase.h"
+#include "fs.h"
#include "key.h"
#include "pubkey.h"
#include "txdb.h"
#include "txmempool.h"
-#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
/** Basic testing setup.
@@ -27,10 +27,12 @@ struct BasicTestingSetup {
/** Testing setup that configures a complete environment.
* Included are data directory, coins database, script check threads setup.
*/
+class CConnman;
struct TestingSetup: public BasicTestingSetup {
CCoinsViewDB *pcoinsdbview;
- boost::filesystem::path pathTemp;
+ fs::path pathTemp;
boost::thread_group threadGroup;
+ CConnman* connman;
TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~TestingSetup();
@@ -59,33 +61,28 @@ struct TestChain100Setup : public TestingSetup {
};
class CTxMemPoolEntry;
-class CTxMemPool;
struct TestMemPoolEntryHelper
{
// Default values
CAmount nFee;
int64_t nTime;
- double dPriority;
unsigned int nHeight;
- bool hadNoDependencies;
bool spendsCoinbase;
unsigned int sigOpCost;
LockPoints lp;
TestMemPoolEntryHelper() :
- nFee(0), nTime(0), dPriority(0.0), nHeight(1),
- hadNoDependencies(false), spendsCoinbase(false), sigOpCost(4) { }
+ nFee(0), nTime(0), nHeight(1),
+ spendsCoinbase(false), sigOpCost(4) { }
- CTxMemPoolEntry FromTx(CMutableTransaction &tx, CTxMemPool *pool = NULL);
- CTxMemPoolEntry FromTx(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 &HadNoDependencies(bool _hnd) { hadNoDependencies = _hnd; return *this; }
TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; }
};
diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp
new file mode 100644
index 0000000000..c4983f6f5c
--- /dev/null
+++ b/src/test/test_bitcoin_fuzzy.cpp
@@ -0,0 +1,258 @@
+// 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.
+
+#if defined(HAVE_CONFIG_H)
+#include "config/bitcoin-config.h"
+#endif
+
+#include "consensus/merkle.h"
+#include "primitives/block.h"
+#include "script/script.h"
+#include "addrman.h"
+#include "chain.h"
+#include "coins.h"
+#include "compressor.h"
+#include "net.h"
+#include "protocol.h"
+#include "streams.h"
+#include "undo.h"
+#include "version.h"
+#include "pubkey.h"
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <vector>
+
+enum TEST_ID {
+ CBLOCK_DESERIALIZE=0,
+ CTRANSACTION_DESERIALIZE,
+ CBLOCKLOCATOR_DESERIALIZE,
+ CBLOCKMERKLEROOT,
+ CADDRMAN_DESERIALIZE,
+ CBLOCKHEADER_DESERIALIZE,
+ CBANENTRY_DESERIALIZE,
+ CTXUNDO_DESERIALIZE,
+ CBLOCKUNDO_DESERIALIZE,
+ CCOINS_DESERIALIZE,
+ CNETADDR_DESERIALIZE,
+ CSERVICE_DESERIALIZE,
+ CMESSAGEHEADER_DESERIALIZE,
+ CADDRESS_DESERIALIZE,
+ CINV_DESERIALIZE,
+ CBLOOMFILTER_DESERIALIZE,
+ CDISKBLOCKINDEX_DESERIALIZE,
+ CTXOUTCOMPRESSOR_DESERIALIZE,
+ TEST_ID_END
+};
+
+bool read_stdin(std::vector<char> &data) {
+ char buffer[1024];
+ ssize_t length=0;
+ while((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
+ data.insert(data.end(), buffer, buffer+length);
+
+ if (data.size() > (1<<20)) return false;
+ }
+ return length==0;
+}
+
+int main(int argc, char **argv)
+{
+ ECCVerifyHandle globalVerifyHandle;
+ std::vector<char> buffer;
+ if (!read_stdin(buffer)) return 0;
+
+ if (buffer.size() < sizeof(uint32_t)) return 0;
+
+ uint32_t test_id = 0xffffffff;
+ memcpy(&test_id, &buffer[0], sizeof(uint32_t));
+ buffer.erase(buffer.begin(), buffer.begin() + sizeof(uint32_t));
+
+ if (test_id >= TEST_ID_END) return 0;
+
+ CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
+ try {
+ int nVersion;
+ ds >> nVersion;
+ ds.SetVersion(nVersion);
+ } catch (const std::ios_base::failure& e) {
+ return 0;
+ }
+
+ switch(test_id) {
+ case CBLOCK_DESERIALIZE:
+ {
+ try
+ {
+ CBlock block;
+ ds >> block;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CTRANSACTION_DESERIALIZE:
+ {
+ try
+ {
+ CTransaction tx(deserialize, ds);
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CBLOCKLOCATOR_DESERIALIZE:
+ {
+ try
+ {
+ CBlockLocator bl;
+ ds >> bl;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CBLOCKMERKLEROOT:
+ {
+ try
+ {
+ CBlock block;
+ ds >> block;
+ bool mutated;
+ BlockMerkleRoot(block, &mutated);
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CADDRMAN_DESERIALIZE:
+ {
+ try
+ {
+ CAddrMan am;
+ ds >> am;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CBLOCKHEADER_DESERIALIZE:
+ {
+ try
+ {
+ CBlockHeader bh;
+ ds >> bh;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CBANENTRY_DESERIALIZE:
+ {
+ try
+ {
+ CBanEntry be;
+ ds >> be;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CTXUNDO_DESERIALIZE:
+ {
+ try
+ {
+ CTxUndo tu;
+ ds >> tu;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CBLOCKUNDO_DESERIALIZE:
+ {
+ try
+ {
+ CBlockUndo bu;
+ ds >> bu;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CCOINS_DESERIALIZE:
+ {
+ try
+ {
+ CCoins block;
+ ds >> block;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CNETADDR_DESERIALIZE:
+ {
+ try
+ {
+ CNetAddr na;
+ ds >> na;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CSERVICE_DESERIALIZE:
+ {
+ try
+ {
+ CService s;
+ ds >> s;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CMESSAGEHEADER_DESERIALIZE:
+ {
+ CMessageHeader::MessageStartChars pchMessageStart = {0x00, 0x00, 0x00, 0x00};
+ try
+ {
+ CMessageHeader mh(pchMessageStart);
+ ds >> mh;
+ if (!mh.IsValid(pchMessageStart)) {return 0;}
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CADDRESS_DESERIALIZE:
+ {
+ try
+ {
+ CAddress a;
+ ds >> a;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CINV_DESERIALIZE:
+ {
+ try
+ {
+ CInv i;
+ ds >> i;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CBLOOMFILTER_DESERIALIZE:
+ {
+ try
+ {
+ CBloomFilter bf;
+ ds >> bf;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CDISKBLOCKINDEX_DESERIALIZE:
+ {
+ try
+ {
+ CDiskBlockIndex dbi;
+ ds >> dbi;
+ } catch (const std::ios_base::failure& e) {return 0;}
+ break;
+ }
+ case CTXOUTCOMPRESSOR_DESERIALIZE:
+ {
+ CTxOut to;
+ CTxOutCompressor toc(to);
+ try
+ {
+ ds >> toc;
+ } catch (const std::ios_base::failure& e) {return 0;}
+
+ break;
+ }
+ default:
+ return 0;
+ }
+ return 0;
+}
+
diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp
new file mode 100644
index 0000000000..34beef5539
--- /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;
+
+void Shutdown(void* parg)
+{
+ exit(EXIT_SUCCESS);
+}
+
+void StartShutdown()
+{
+ exit(EXIT_SUCCESS);
+}
+
+bool ShutdownRequested()
+{
+ return false;
+}
diff --git a/src/test/test_random.h b/src/test/test_random.h
new file mode 100644
index 0000000000..318c44df4d
--- /dev/null
+++ b/src/test/test_random.h
@@ -0,0 +1,29 @@
+// 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 uint256 insecure_rand_seed;
+extern FastRandomContext insecure_rand_ctx;
+
+static inline void seed_insecure_rand(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 insecure_rand(void)
+{
+ return insecure_rand_ctx.rand32();
+}
+
+#endif
diff --git a/src/test/testutil.cpp b/src/test/testutil.cpp
index 304cffb798..591d0bf302 100644
--- a/src/test/testutil.cpp
+++ b/src/test/testutil.cpp
@@ -8,26 +8,8 @@
#include <shlobj.h>
#endif
-#include <boost/filesystem.hpp>
+#include "fs.h"
-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
+fs::path GetTempPath() {
+ return fs::temp_directory_path();
}
diff --git a/src/test/testutil.h b/src/test/testutil.h
index 5875dc50e6..cbe784d640 100644
--- a/src/test/testutil.h
+++ b/src/test/testutil.h
@@ -8,8 +8,8 @@
#ifndef BITCOIN_TEST_TESTUTIL_H
#define BITCOIN_TEST_TESTUTIL_H
-#include <boost/filesystem/path.hpp>
+#include "fs.h"
-boost::filesystem::path GetTempPath();
+fs::path GetTempPath();
#endif // BITCOIN_TEST_TESTUTIL_H
diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp
index 1224ff8454..34863fd9d0 100644
--- a/src/test/timedata_tests.cpp
+++ b/src/test/timedata_tests.cpp
@@ -7,8 +7,6 @@
#include <boost/test/unit_test.hpp>
-using namespace std;
-
BOOST_FIXTURE_TEST_SUITE(timedata_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(util_MedianFilter)
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index fd4f174b40..3b5da4980b 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -7,11 +7,12 @@
#include "test/test_bitcoin.h"
#include "clientversion.h"
+#include "checkqueue.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "key.h"
#include "keystore.h"
-#include "main.h" // For CheckTransaction
+#include "validation.h" // For CheckTransaction
#include "policy/policy.h"
#include "script/script.h"
#include "script/sign.h"
@@ -31,39 +32,40 @@
#include <univalue.h>
-using namespace std;
-
-typedef vector<unsigned char> valtype;
+typedef std::vector<unsigned char> valtype;
// In script_tests.cpp
extern UniValue read_json(const std::string& jsondata);
-static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
- (string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE)
- (string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH)
- (string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC)
- (string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG)
- (string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S)
- (string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY)
- (string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA)
- (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY)
- (string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
- (string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK)
- (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
- (string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
- (string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS)
- (string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
-
-unsigned int ParseScriptFlags(string strFlags)
+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);
+
+unsigned int ParseScriptFlags(std::string strFlags)
{
if (strFlags.empty()) {
return 0;
}
unsigned int flags = 0;
- vector<string> words;
+ std::vector<std::string> words;
boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(","));
- BOOST_FOREACH(string word, words)
+ BOOST_FOREACH(std::string word, words)
{
if (!mapFlagNames.count(word))
BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
@@ -73,13 +75,13 @@ unsigned int ParseScriptFlags(string strFlags)
return flags;
}
-string FormatScriptFlags(unsigned int flags)
+std::string FormatScriptFlags(unsigned int flags)
{
if (flags == 0) {
return "";
}
- string ret;
- std::map<string, unsigned int>::const_iterator it = mapFlagNames.begin();
+ std::string ret;
+ std::map<std::string, unsigned int>::const_iterator it = mapFlagNames.begin();
while (it != mapFlagNames.end()) {
if (flags & it->second) {
ret += it->first + ",";
@@ -105,7 +107,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
ScriptError err;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
- string strTest = test.write();
+ std::string strTest = test.write();
if (test[0].isArray())
{
if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
@@ -114,8 +116,8 @@ BOOST_AUTO_TEST_CASE(tx_valid)
continue;
}
- map<COutPoint, CScript> mapprevOutScriptPubKeys;
- map<COutPoint, int64_t> mapprevOutValues;
+ std::map<COutPoint, CScript> mapprevOutScriptPubKeys;
+ std::map<COutPoint, int64_t> mapprevOutValues;
UniValue inputs = test[0].get_array();
bool fValid = true;
for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
@@ -144,15 +146,15 @@ BOOST_AUTO_TEST_CASE(tx_valid)
continue;
}
- string transaction = test[1].get_str();
+ std::string transaction = test[1].get_str();
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
- CTransaction tx;
- stream >> tx;
+ CTransaction tx(deserialize, stream);
CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
BOOST_CHECK(state.IsValid());
+ PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
@@ -166,9 +168,9 @@ BOOST_AUTO_TEST_CASE(tx_valid)
amount = mapprevOutValues[tx.vin[i].prevout];
}
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
- const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
+ const CScriptWitness *witness = &tx.vin[i].scriptWitness;
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err),
+ witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err),
strTest);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
@@ -187,10 +189,12 @@ 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];
- string strTest = test.write();
+ std::string strTest = test.write();
if (test[0].isArray())
{
if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
@@ -199,8 +203,8 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
continue;
}
- map<COutPoint, CScript> mapprevOutScriptPubKeys;
- map<COutPoint, int64_t> mapprevOutValues;
+ std::map<COutPoint, CScript> mapprevOutScriptPubKeys;
+ std::map<COutPoint, int64_t> mapprevOutValues;
UniValue inputs = test[0].get_array();
bool fValid = true;
for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
@@ -229,14 +233,14 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
continue;
}
- string transaction = test[1].get_str();
+ std::string transaction = test[1].get_str();
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION );
- CTransaction tx;
- stream >> tx;
+ CTransaction tx(deserialize, stream);
CValidationState state;
fValid = CheckTransaction(tx, state) && state.IsValid();
+ PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
@@ -250,9 +254,9 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
if (mapprevOutValues.count(tx.vin[i].prevout)) {
amount = mapprevOutValues[tx.vin[i].prevout];
}
- const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
+ const CScriptWitness *witness = &tx.vin[i].scriptWitness;
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err);
+ witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err);
}
BOOST_CHECK_MESSAGE(!fValid, strTest);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
@@ -264,7 +268,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
{
// Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436)
unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00};
- vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
+ std::vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
CMutableTransaction tx;
stream >> tx;
@@ -340,36 +344,33 @@ BOOST_AUTO_TEST_CASE(test_Get)
BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);
}
-void CreateCreditAndSpend(const CKeyStore& keystore, const CScript& outscript, CTransaction& output, CMutableTransaction& input, bool success = true)
+void CreateCreditAndSpend(const CKeyStore& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true)
{
CMutableTransaction outputm;
outputm.nVersion = 1;
outputm.vin.resize(1);
outputm.vin[0].prevout.SetNull();
outputm.vin[0].scriptSig = CScript();
- outputm.wit.vtxinwit.resize(1);
outputm.vout.resize(1);
outputm.vout[0].nValue = 1;
outputm.vout[0].scriptPubKey = outscript;
CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION);
ssout << outputm;
ssout >> output;
- assert(output.vin.size() == 1);
- assert(output.vin[0] == outputm.vin[0]);
- assert(output.vout.size() == 1);
- assert(output.vout[0] == outputm.vout[0]);
- assert(output.wit.vtxinwit.size() == 0);
+ assert(output->vin.size() == 1);
+ assert(output->vin[0] == outputm.vin[0]);
+ assert(output->vout.size() == 1);
+ assert(output->vout[0] == outputm.vout[0]);
CMutableTransaction inputm;
inputm.nVersion = 1;
inputm.vin.resize(1);
- inputm.vin[0].prevout.hash = output.GetHash();
+ inputm.vin[0].prevout.hash = output->GetHash();
inputm.vin[0].prevout.n = 0;
- inputm.wit.vtxinwit.resize(1);
inputm.vout.resize(1);
inputm.vout[0].nValue = 1;
inputm.vout[0].scriptPubKey = CScript();
- bool ret = SignSignature(keystore, output, inputm, 0, SIGHASH_ALL);
+ bool ret = SignSignature(keystore, *output, inputm, 0, SIGHASH_ALL);
assert(ret == success);
CDataStream ssin(SER_NETWORK, PROTOCOL_VERSION);
ssin << inputm;
@@ -378,24 +379,18 @@ void CreateCreditAndSpend(const CKeyStore& keystore, const CScript& outscript, C
assert(input.vin[0] == inputm.vin[0]);
assert(input.vout.size() == 1);
assert(input.vout[0] == inputm.vout[0]);
- if (inputm.wit.IsNull()) {
- assert(input.wit.IsNull());
- } else {
- assert(!input.wit.IsNull());
- assert(input.wit.vtxinwit.size() == 1);
- assert(input.wit.vtxinwit[0].scriptWitness.stack == inputm.wit.vtxinwit[0].scriptWitness.stack);
- }
+ assert(input.vin[0].scriptWitness.stack == inputm.vin[0].scriptWitness.stack);
}
-void CheckWithFlag(const CTransaction& output, const CMutableTransaction& input, int flags, bool success)
+void CheckWithFlag(const CTransactionRef& output, const CMutableTransaction& input, int flags, bool success)
{
ScriptError error;
CTransaction inputi(input);
- bool ret = VerifyScript(inputi.vin[0].scriptSig, output.vout[0].scriptPubKey, inputi.wit.vtxinwit.size() > 0 ? &inputi.wit.vtxinwit[0].scriptWitness : NULL, flags, TransactionSignatureChecker(&inputi, 0, output.vout[0].nValue), &error);
+ bool ret = VerifyScript(inputi.vin[0].scriptSig, output->vout[0].scriptPubKey, &inputi.vin[0].scriptWitness, flags, TransactionSignatureChecker(&inputi, 0, output->vout[0].nValue), &error);
assert(ret == success);
}
-static CScript PushAll(const vector<valtype>& values)
+static CScript PushAll(const std::vector<valtype>& values)
{
CScript result;
BOOST_FOREACH(const valtype& v, values) {
@@ -412,13 +407,93 @@ static CScript PushAll(const vector<valtype>& values)
void ReplaceRedeemScript(CScript& script, const CScript& redeemScript)
{
- vector<valtype> stack;
+ std::vector<valtype> stack;
EvalScript(stack, script, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE);
assert(stack.size() > 0);
stack.back() = std::vector<unsigned char>(redeemScript.begin(), redeemScript.end());
script = PushAll(stack);
}
+BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
+ CMutableTransaction mtx;
+ mtx.nVersion = 1;
+
+ CKey key;
+ key.MakeNewKey(true); // Need to use compressed keys in segwit or the signing will fail
+ CBasicKeyStore keystore;
+ keystore.AddKeyPubKey(key, key.GetPubKey());
+ CKeyID hash = key.GetPubKey().GetID();
+ CScript scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(hash.begin(), hash.end());
+
+ std::vector<int> sigHashes;
+ sigHashes.push_back(SIGHASH_NONE | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_ALL | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_NONE);
+ sigHashes.push_back(SIGHASH_SINGLE);
+ sigHashes.push_back(SIGHASH_ALL);
+
+ // create a big transaction of 4500 inputs signed by the same key
+ for(uint32_t ij = 0; ij < 4500; ij++) {
+ uint32_t i = mtx.vin.size();
+ uint256 prevId;
+ prevId.SetHex("0000000000000000000000000000000000000000000000000000000000000100");
+ COutPoint outpoint(prevId, i);
+
+ mtx.vin.resize(mtx.vin.size() + 1);
+ mtx.vin[i].prevout = outpoint;
+ mtx.vin[i].scriptSig = CScript();
+
+ mtx.vout.resize(mtx.vout.size() + 1);
+ mtx.vout[i].nValue = 1000;
+ mtx.vout[i].scriptPubKey = CScript() << OP_1;
+ }
+
+ // sign all inputs
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()));
+ assert(hashSigned);
+ }
+
+ CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION);
+ auto vstream = WithOrVersion(&ssout, 0);
+ vstream << mtx;
+ CTransaction tx(deserialize, vstream);
+
+ // check all inputs concurrently, with the cache
+ PrecomputedTransactionData txdata(tx);
+ boost::thread_group threadGroup;
+ CCheckQueue<CScriptCheck> scriptcheckqueue(128);
+ CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
+
+ 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;
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ CTxOut txout;
+ txout.nValue = 1000;
+ txout.scriptPubKey = scriptPubKey;
+ coins.vout.push_back(txout);
+ }
+
+ 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);
+ vChecks.push_back(CScriptCheck());
+ check.swap(vChecks.back());
+ control.Add(vChecks);
+ }
+
+ bool controlCheck = control.Wait();
+ assert(controlCheck);
+
+ threadGroup.interrupt_all();
+ threadGroup.join_all();
+}
+
BOOST_AUTO_TEST_CASE(test_witness)
{
CBasicKeyStore keystore, keystore2;
@@ -461,7 +536,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
keystore2.AddCScript(GetScriptForWitness(scriptMulti));
keystore2.AddKeyPubKey(key3, pubkey3);
- CTransaction output1, output2;
+ CTransactionRef output1, output2;
CMutableTransaction input1, input2;
SignatureData sigdata;
@@ -540,38 +615,21 @@ BOOST_AUTO_TEST_CASE(test_witness)
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
- // Witness pay-to-uncompressed-pubkey (v1).
- CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey1L), output1, input1);
- CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2);
- CheckWithFlag(output1, input1, 0, true);
- CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
- CheckWithFlag(output1, input2, 0, true);
- CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
- CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
+ // Signing disabled for witness pay-to-uncompressed-pubkey (v1).
+ CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey1L), output1, input1, false);
+ CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2, false);
- // P2SH witness pay-to-uncompressed-pubkey (v1).
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1);
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2);
- ReplaceRedeemScript(input2.vin[0].scriptSig, GetScriptForWitness(scriptPubkey1L));
- CheckWithFlag(output1, input1, 0, true);
- CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
- CheckWithFlag(output1, input2, 0, true);
- CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
- CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
+ // Signing disabled for P2SH witness pay-to-uncompressed-pubkey (v1).
+ CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1, false);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2, false);
// Normal 2-of-2 multisig
CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false);
CheckWithFlag(output1, input1, 0, false);
CreateCreditAndSpend(keystore2, scriptMulti, output2, input2, false);
CheckWithFlag(output2, input2, 0, false);
- BOOST_CHECK(output1 == output2);
- UpdateTransaction(input1, 0, CombineSignatures(output1.vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1.vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
+ BOOST_CHECK(*output1 == *output2);
+ UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
// P2SH 2-of-2 multisig
@@ -581,8 +639,8 @@ BOOST_AUTO_TEST_CASE(test_witness)
CreateCreditAndSpend(keystore2, GetScriptForDestination(CScriptID(scriptMulti)), output2, input2, false);
CheckWithFlag(output2, input2, 0, true);
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, false);
- BOOST_CHECK(output1 == output2);
- UpdateTransaction(input1, 0, CombineSignatures(output1.vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1.vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
+ BOOST_CHECK(*output1 == *output2);
+ UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
@@ -593,8 +651,8 @@ BOOST_AUTO_TEST_CASE(test_witness)
CreateCreditAndSpend(keystore2, GetScriptForWitness(scriptMulti), output2, input2, false);
CheckWithFlag(output2, input2, 0, true);
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false);
- BOOST_CHECK(output1 == output2);
- UpdateTransaction(input1, 0, CombineSignatures(output1.vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1.vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
+ BOOST_CHECK(*output1 == *output2);
+ UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true);
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
@@ -605,8 +663,8 @@ BOOST_AUTO_TEST_CASE(test_witness)
CreateCreditAndSpend(keystore2, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptMulti))), output2, input2, false);
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, true);
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false);
- BOOST_CHECK(output1 == output2);
- UpdateTransaction(input1, 0, CombineSignatures(output1.vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1.vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
+ BOOST_CHECK(*output1 == *output2);
+ UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true);
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
}
@@ -630,11 +688,11 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
key.MakeNewKey(true);
t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
- string reason;
+ std::string reason;
BOOST_CHECK(IsStandardTx(t, reason));
// Check dust with default relay fee:
- CAmount nDustThreshold = 182 * minRelayTxFee.GetFeePerK()/1000 * 3;
+ CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK()/1000 * 3;
BOOST_CHECK_EQUAL(nDustThreshold, 546);
// dust:
t.vout[0].nValue = nDustThreshold - 1;
@@ -645,14 +703,14 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
// Check dust with odd relay fee to verify rounding:
// nDustThreshold = 182 * 1234 / 1000 * 3
- minRelayTxFee = CFeeRate(1234);
+ dustRelayFee = CFeeRate(1234);
// dust:
t.vout[0].nValue = 672 - 1;
BOOST_CHECK(!IsStandardTx(t, reason));
// not dust:
t.vout[0].nValue = 672;
BOOST_CHECK(IsStandardTx(t, reason));
- minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
+ dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
t.vout[0].scriptPubKey = CScript() << OP_1;
BOOST_CHECK(!IsStandardTx(t, reason));
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 76e4e7a4be..c5367208ba 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
#include "consensus/validation.h"
#include "key.h"
-#include "main.h"
+#include "validation.h"
#include "miner.h"
#include "pubkey.h"
#include "txmempool.h"
@@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx)
LOCK(cs_main);
CValidationState state;
- return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, 0);
+ return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), false, NULL, NULL, true, 0);
}
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
@@ -39,6 +39,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
spends.resize(2);
for (int i = 0; i < 2; i++)
{
+ spends[i].nVersion = 1;
spends[i].vin.resize(1);
spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetHash();
spends[i].vin[0].prevout.n = 0;
diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp
index da0a3d73e0..70d83a2e54 100644
--- a/src/test/uint256_tests.cpp
+++ b/src/test/uint256_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
#include "arith_uint256.h"
@@ -184,25 +184,25 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G
BOOST_CHECK(OneL.begin() + 32 == OneL.end());
BOOST_CHECK(MaxL.begin() + 32 == MaxL.end());
BOOST_CHECK(TmpL.begin() + 32 == TmpL.end());
- BOOST_CHECK(R1L.GetSerializeSize(0,PROTOCOL_VERSION) == 32);
- BOOST_CHECK(ZeroL.GetSerializeSize(0,PROTOCOL_VERSION) == 32);
+ BOOST_CHECK(GetSerializeSize(R1L, 0, PROTOCOL_VERSION) == 32);
+ BOOST_CHECK(GetSerializeSize(ZeroL, 0, PROTOCOL_VERSION) == 32);
- std::stringstream ss;
- R1L.Serialize(ss,0,PROTOCOL_VERSION);
+ CDataStream ss(0, PROTOCOL_VERSION);
+ ss << R1L;
BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+32));
- TmpL.Unserialize(ss,0,PROTOCOL_VERSION);
+ ss >> TmpL;
BOOST_CHECK(R1L == TmpL);
- ss.str("");
- ZeroL.Serialize(ss,0,PROTOCOL_VERSION);
+ ss.clear();
+ ss << ZeroL;
BOOST_CHECK(ss.str() == std::string(ZeroArray,ZeroArray+32));
- TmpL.Unserialize(ss,0,PROTOCOL_VERSION);
+ ss >> TmpL;
BOOST_CHECK(ZeroL == TmpL);
- ss.str("");
- MaxL.Serialize(ss,0,PROTOCOL_VERSION);
+ ss.clear();
+ ss << MaxL;
BOOST_CHECK(ss.str() == std::string(MaxArray,MaxArray+32));
- TmpL.Unserialize(ss,0,PROTOCOL_VERSION);
+ ss >> TmpL;
BOOST_CHECK(MaxL == TmpL);
- ss.str("");
+ ss.clear();
BOOST_CHECK(R1S.GetHex() == R1S.ToString());
BOOST_CHECK(R2S.GetHex() == R2S.ToString());
@@ -230,24 +230,24 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G
BOOST_CHECK(OneS.begin() + 20 == OneS.end());
BOOST_CHECK(MaxS.begin() + 20 == MaxS.end());
BOOST_CHECK(TmpS.begin() + 20 == TmpS.end());
- BOOST_CHECK(R1S.GetSerializeSize(0,PROTOCOL_VERSION) == 20);
- BOOST_CHECK(ZeroS.GetSerializeSize(0,PROTOCOL_VERSION) == 20);
+ BOOST_CHECK(GetSerializeSize(R1S, 0, PROTOCOL_VERSION) == 20);
+ BOOST_CHECK(GetSerializeSize(ZeroS, 0, PROTOCOL_VERSION) == 20);
- R1S.Serialize(ss,0,PROTOCOL_VERSION);
+ ss << R1S;
BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+20));
- TmpS.Unserialize(ss,0,PROTOCOL_VERSION);
+ ss >> TmpS;
BOOST_CHECK(R1S == TmpS);
- ss.str("");
- ZeroS.Serialize(ss,0,PROTOCOL_VERSION);
+ ss.clear();
+ ss << ZeroS;
BOOST_CHECK(ss.str() == std::string(ZeroArray,ZeroArray+20));
- TmpS.Unserialize(ss,0,PROTOCOL_VERSION);
+ ss >> TmpS;
BOOST_CHECK(ZeroS == TmpS);
- ss.str("");
- MaxS.Serialize(ss,0,PROTOCOL_VERSION);
+ ss.clear();
+ ss << MaxS;
BOOST_CHECK(ss.str() == std::string(MaxArray,MaxArray+20));
- TmpS.Unserialize(ss,0,PROTOCOL_VERSION);
+ ss >> TmpS;
BOOST_CHECK(MaxS == TmpS);
- ss.str("");
+ ss.clear();
}
BOOST_AUTO_TEST_CASE( conversion )
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
index 45d480c816..dffe8e55a8 100644
--- a/src/test/univalue_tests.cpp
+++ b/src/test/univalue_tests.cpp
@@ -1,5 +1,5 @@
-// Copyright 2014 BitPay, Inc.
-// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Copyright (c) 2014 BitPay Inc.
+// Copyright (c) 2014-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.
@@ -12,8 +12,6 @@
#include <boost/test/unit_test.hpp>
-using namespace std;
-
BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(univalue_constructor)
@@ -53,7 +51,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
BOOST_CHECK(v7.isNum());
BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
- string vs("yawn");
+ std::string vs("yawn");
UniValue v8(vs);
BOOST_CHECK(v8.isStr());
BOOST_CHECK_EQUAL(v8.getValStr(), "yawn");
@@ -69,41 +67,41 @@ BOOST_AUTO_TEST_CASE(univalue_typecheck)
UniValue v1;
BOOST_CHECK(v1.setNumStr("1"));
BOOST_CHECK(v1.isNum());
- BOOST_CHECK_THROW(v1.get_bool(), runtime_error);
+ BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);
UniValue v2;
BOOST_CHECK(v2.setBool(true));
BOOST_CHECK_EQUAL(v2.get_bool(), true);
- BOOST_CHECK_THROW(v2.get_int(), runtime_error);
+ BOOST_CHECK_THROW(v2.get_int(), std::runtime_error);
UniValue v3;
BOOST_CHECK(v3.setNumStr("32482348723847471234"));
- BOOST_CHECK_THROW(v3.get_int64(), runtime_error);
+ BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error);
BOOST_CHECK(v3.setNumStr("1000"));
BOOST_CHECK_EQUAL(v3.get_int64(), 1000);
UniValue v4;
BOOST_CHECK(v4.setNumStr("2147483648"));
BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);
- BOOST_CHECK_THROW(v4.get_int(), runtime_error);
+ BOOST_CHECK_THROW(v4.get_int(), std::runtime_error);
BOOST_CHECK(v4.setNumStr("1000"));
BOOST_CHECK_EQUAL(v4.get_int(), 1000);
- BOOST_CHECK_THROW(v4.get_str(), runtime_error);
+ BOOST_CHECK_THROW(v4.get_str(), std::runtime_error);
BOOST_CHECK_EQUAL(v4.get_real(), 1000);
- BOOST_CHECK_THROW(v4.get_array(), runtime_error);
- BOOST_CHECK_THROW(v4.getKeys(), runtime_error);
- BOOST_CHECK_THROW(v4.getValues(), runtime_error);
- BOOST_CHECK_THROW(v4.get_obj(), runtime_error);
+ BOOST_CHECK_THROW(v4.get_array(), std::runtime_error);
+ BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error);
+ BOOST_CHECK_THROW(v4.getValues(), std::runtime_error);
+ BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error);
UniValue v5;
BOOST_CHECK(v5.read("[true, 10]"));
BOOST_CHECK_NO_THROW(v5.get_array());
std::vector<UniValue> vals = v5.getValues();
- BOOST_CHECK_THROW(vals[0].get_int(), runtime_error);
+ BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error);
BOOST_CHECK_EQUAL(vals[0].get_bool(), true);
BOOST_CHECK_EQUAL(vals[1].get_int(), 10);
- BOOST_CHECK_THROW(vals[1].get_bool(), runtime_error);
+ BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error);
}
BOOST_AUTO_TEST_CASE(univalue_set)
@@ -172,13 +170,13 @@ BOOST_AUTO_TEST_CASE(univalue_array)
UniValue v((int64_t)1023LL);
BOOST_CHECK(arr.push_back(v));
- string vStr("zippy");
+ std::string vStr("zippy");
BOOST_CHECK(arr.push_back(vStr));
const char *s = "pippy";
BOOST_CHECK(arr.push_back(s));
- vector<UniValue> vec;
+ std::vector<UniValue> vec;
v.setStr("boing");
vec.push_back(v);
@@ -206,7 +204,7 @@ BOOST_AUTO_TEST_CASE(univalue_array)
BOOST_AUTO_TEST_CASE(univalue_object)
{
UniValue obj(UniValue::VOBJ);
- string strKey, strVal;
+ std::string strKey, strVal;
UniValue v;
strKey = "age";
@@ -266,7 +264,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
BOOST_CHECK(!obj.exists("nyuknyuknyuk"));
- map<string, UniValue::VType> objTypes;
+ std::map<std::string, UniValue::VType> objTypes;
objTypes["age"] = UniValue::VNUM;
objTypes["first"] = UniValue::VSTR;
objTypes["last"] = UniValue::VSTR;
@@ -294,7 +292,7 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite)
UniValue v;
BOOST_CHECK(v.read(json1));
- string strJson1(json1);
+ std::string strJson1(json1);
BOOST_CHECK(v.read(strJson1));
BOOST_CHECK(v.isArray());
@@ -333,4 +331,3 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite)
}
BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index e467a4171d..10330c0c23 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
@@ -6,19 +6,17 @@
#include "clientversion.h"
#include "primitives/transaction.h"
-#include "random.h"
#include "sync.h"
#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>
-using namespace std;
-
BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(util_criticalsection)
@@ -100,52 +98,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(mapArgs.count("-a") && mapArgs.count("-b") && mapArgs.count("-ccc")
- && !mapArgs.count("f") && !mapArgs.count("-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["-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)
@@ -243,23 +256,18 @@ BOOST_AUTO_TEST_CASE(util_IsHex)
BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
{
- int i;
- int count=0;
-
seed_insecure_rand(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;
- count = 0;
+ int count = 0;
//How often does it get a zero from the uniform range [0,mod)?
- for (i=0;i<10000;i++)
- {
+ for (int i = 0; i < 10000; i++) {
uint32_t rval;
do{
rval=insecure_rand()&mask;
@@ -326,7 +334,7 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
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));
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index 1f86a06a3f..79405ec4d1 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -1,13 +1,13 @@
-// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Copyright (c) 2014-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 "chain.h"
-#include "random.h"
#include "versionbits.h"
#include "test/test_bitcoin.h"
+#include "test/test_random.h"
#include "chainparams.h"
-#include "main.h"
+#include "validation.h"
#include "consensus/params.h"
#include <boost/test/unit_test.hpp>
@@ -30,6 +30,7 @@ public:
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const { 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); }
};
#define CHECKERS 6
@@ -78,6 +79,16 @@ public:
return *this;
}
+ 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));
+ }
+ }
+ num++;
+ return *this;
+ }
+
VersionBitsTester& TestDefined() {
for (int i = 0; i < CHECKERS; i++) {
if ((insecure_rand() & ((1 << i) - 1)) == 0) {
@@ -137,57 +148,69 @@ BOOST_AUTO_TEST_CASE(versionbits_test)
{
for (int i = 0; i < 64; i++) {
// DEFINED -> FAILED
- VersionBitsTester().TestDefined()
- .Mine(1, TestTime(1), 0x100).TestDefined()
- .Mine(11, TestTime(11), 0x100).TestDefined()
- .Mine(989, TestTime(989), 0x100).TestDefined()
- .Mine(999, TestTime(20000), 0x100).TestDefined()
- .Mine(1000, TestTime(20000), 0x100).TestFailed()
- .Mine(1999, TestTime(30001), 0x100).TestFailed()
- .Mine(2000, TestTime(30002), 0x100).TestFailed()
- .Mine(2001, TestTime(30003), 0x100).TestFailed()
- .Mine(2999, TestTime(30004), 0x100).TestFailed()
- .Mine(3000, TestTime(30005), 0x100).TestFailed()
+ VersionBitsTester().TestDefined().TestStateSinceHeight(0)
+ .Mine(1, TestTime(1), 0x100).TestDefined().TestStateSinceHeight(0)
+ .Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0)
+ .Mine(989, TestTime(989), 0x100).TestDefined().TestStateSinceHeight(0)
+ .Mine(999, TestTime(20000), 0x100).TestDefined().TestStateSinceHeight(0)
+ .Mine(1000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(1000)
+ .Mine(1999, TestTime(30001), 0x100).TestFailed().TestStateSinceHeight(1000)
+ .Mine(2000, TestTime(30002), 0x100).TestFailed().TestStateSinceHeight(1000)
+ .Mine(2001, TestTime(30003), 0x100).TestFailed().TestStateSinceHeight(1000)
+ .Mine(2999, TestTime(30004), 0x100).TestFailed().TestStateSinceHeight(1000)
+ .Mine(3000, TestTime(30005), 0x100).TestFailed().TestStateSinceHeight(1000)
// DEFINED -> STARTED -> FAILED
- .Reset().TestDefined()
- .Mine(1, TestTime(1), 0).TestDefined()
- .Mine(1000, TestTime(10000) - 1, 0x100).TestDefined() // One second more and it would be defined
- .Mine(2000, TestTime(10000), 0x100).TestStarted() // So that's what happens the next period
- .Mine(2051, TestTime(10010), 0).TestStarted() // 51 old blocks
- .Mine(2950, TestTime(10020), 0x100).TestStarted() // 899 new blocks
- .Mine(3000, TestTime(20000), 0).TestFailed() // 50 old blocks (so 899 out of the past 1000)
- .Mine(4000, TestTime(20010), 0x100).TestFailed()
+ .Reset().TestDefined().TestStateSinceHeight(0)
+ .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(1000, TestTime(10000) - 1, 0x100).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
+ .Mine(2000, TestTime(10000), 0x100).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period
+ .Mine(2051, TestTime(10010), 0).TestStarted().TestStateSinceHeight(2000) // 51 old blocks
+ .Mine(2950, TestTime(10020), 0x100).TestStarted().TestStateSinceHeight(2000) // 899 new blocks
+ .Mine(3000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(3000) // 50 old blocks (so 899 out of the past 1000)
+ .Mine(4000, TestTime(20010), 0x100).TestFailed().TestStateSinceHeight(3000)
// DEFINED -> STARTED -> FAILED while threshold reached
- .Reset().TestDefined()
- .Mine(1, TestTime(1), 0).TestDefined()
- .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined
- .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period
- .Mine(2999, TestTime(30000), 0x100).TestStarted() // 999 new blocks
- .Mine(3000, TestTime(30000), 0x100).TestFailed() // 1 new block (so 1000 out of the past 1000 are new)
- .Mine(3999, TestTime(30001), 0).TestFailed()
- .Mine(4000, TestTime(30002), 0).TestFailed()
- .Mine(14333, TestTime(30003), 0).TestFailed()
- .Mine(24000, TestTime(40000), 0).TestFailed()
+ .Reset().TestDefined().TestStateSinceHeight(0)
+ .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
+ .Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period
+ .Mine(2999, TestTime(30000), 0x100).TestStarted().TestStateSinceHeight(2000) // 999 new blocks
+ .Mine(3000, TestTime(30000), 0x100).TestFailed().TestStateSinceHeight(3000) // 1 new block (so 1000 out of the past 1000 are new)
+ .Mine(3999, TestTime(30001), 0).TestFailed().TestStateSinceHeight(3000)
+ .Mine(4000, TestTime(30002), 0).TestFailed().TestStateSinceHeight(3000)
+ .Mine(14333, TestTime(30003), 0).TestFailed().TestStateSinceHeight(3000)
+ .Mine(24000, TestTime(40000), 0).TestFailed().TestStateSinceHeight(3000)
// DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE
.Reset().TestDefined()
- .Mine(1, TestTime(1), 0).TestDefined()
- .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined
- .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period
- .Mine(2050, TestTime(10010), 0x200).TestStarted() // 50 old blocks
- .Mine(2950, TestTime(10020), 0x100).TestStarted() // 900 new blocks
- .Mine(2999, TestTime(19999), 0x200).TestStarted() // 49 old blocks
- .Mine(3000, TestTime(29999), 0x200).TestLockedIn() // 1 old block (so 900 out of the past 1000)
- .Mine(3999, TestTime(30001), 0).TestLockedIn()
- .Mine(4000, TestTime(30002), 0).TestActive()
- .Mine(14333, TestTime(30003), 0).TestActive()
- .Mine(24000, TestTime(40000), 0).TestActive();
+ .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
+ .Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period
+ .Mine(2050, TestTime(10010), 0x200).TestStarted().TestStateSinceHeight(2000) // 50 old blocks
+ .Mine(2950, TestTime(10020), 0x100).TestStarted().TestStateSinceHeight(2000) // 900 new blocks
+ .Mine(2999, TestTime(19999), 0x200).TestStarted().TestStateSinceHeight(2000) // 49 old blocks
+ .Mine(3000, TestTime(29999), 0x200).TestLockedIn().TestStateSinceHeight(3000) // 1 old block (so 900 out of the past 1000)
+ .Mine(3999, TestTime(30001), 0).TestLockedIn().TestStateSinceHeight(3000)
+ .Mine(4000, TestTime(30002), 0).TestActive().TestStateSinceHeight(4000)
+ .Mine(14333, TestTime(30003), 0).TestActive().TestStateSinceHeight(4000)
+ .Mine(24000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000)
+
+ // DEFINED multiple periods -> STARTED multiple periods -> FAILED
+ .Reset().TestDefined().TestStateSinceHeight(0)
+ .Mine(999, TestTime(999), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(1000, TestTime(1000), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(2000, TestTime(2000), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(3000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
+ .Mine(4000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
+ .Mine(5000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
+ .Mine(6000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(6000)
+ .Mine(7000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(6000);
}
// 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.
@@ -213,7 +236,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;
@@ -270,7 +294,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
diff --git a/src/threadinterrupt.cpp b/src/threadinterrupt.cpp
new file mode 100644
index 0000000000..9d691079ed
--- /dev/null
+++ b/src/threadinterrupt.cpp
@@ -0,0 +1,41 @@
+// 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.
+
+#include "threadinterrupt.h"
+
+CThreadInterrupt::operator bool() const
+{
+ return flag.load(std::memory_order_acquire);
+}
+
+void CThreadInterrupt::reset()
+{
+ flag.store(false, std::memory_order_release);
+}
+
+void CThreadInterrupt::operator()()
+{
+ {
+ std::unique_lock<std::mutex> lock(mut);
+ flag.store(true, std::memory_order_release);
+ }
+ cond.notify_all();
+}
+
+bool CThreadInterrupt::sleep_for(std::chrono::milliseconds rel_time)
+{
+ std::unique_lock<std::mutex> lock(mut);
+ return !cond.wait_for(lock, rel_time, [this]() { return flag.load(std::memory_order_acquire); });
+}
+
+bool CThreadInterrupt::sleep_for(std::chrono::seconds rel_time)
+{
+ return sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(rel_time));
+}
+
+bool CThreadInterrupt::sleep_for(std::chrono::minutes rel_time)
+{
+ return sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(rel_time));
+}
diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h
new file mode 100644
index 0000000000..54e3102808
--- /dev/null
+++ b/src/threadinterrupt.h
@@ -0,0 +1,34 @@
+// Copyright (c) 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_THREADINTERRUPT_H
+#define BITCOIN_THREADINTERRUPT_H
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+/*
+ A helper class for interruptible sleeps. Calling operator() will interrupt
+ any current sleep, and after that point operator bool() will return true
+ until reset.
+*/
+class CThreadInterrupt
+{
+public:
+ explicit operator bool() const;
+ void operator()();
+ void reset();
+ bool sleep_for(std::chrono::milliseconds rel_time);
+ bool sleep_for(std::chrono::seconds rel_time);
+ bool sleep_for(std::chrono::minutes rel_time);
+
+private:
+ std::condition_variable cond;
+ std::mutex mut;
+ std::atomic<bool> flag;
+};
+
+#endif //BITCOIN_THREADINTERRUPT_H
diff --git a/src/timedata.cpp b/src/timedata.cpp
index b6bcf86fbf..ec74912703 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Copyright (c) 2014-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.
@@ -8,16 +8,15 @@
#include "timedata.h"
-#include "netbase.h"
+#include "netaddress.h"
#include "sync.h"
#include "ui_interface.h"
#include "util.h"
#include "utilstrencodings.h"
+#include "warnings.h"
#include <boost/foreach.hpp>
-using namespace std;
-
static CCriticalSection cs_nTimeOffset;
static int64_t nTimeOffset = 0;
@@ -50,7 +49,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)
@@ -59,7 +58,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):
//
@@ -103,17 +102,20 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
if (!fMatch)
{
fDone = true;
- string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), _(PACKAGE_NAME));
- strMiscWarning = strMessage;
+ std::string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), _(PACKAGE_NAME));
+ SetMiscWarning(strMessage);
uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
}
}
}
-
- 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)) {
+ BOOST_FOREACH(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 9f2499c85c..bc5451b19b 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 The Bitcoin Core developers
+// Copyright (c) 2014-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.
@@ -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 c6ec0419b3..5022d46809 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -67,7 +67,9 @@
// weekday, month, day, hour, min);
// std::cout << date;
//
-// These are the three primary interface functions.
+// These are the three primary interface functions. There is also a
+// convenience function printfln() which appends a newline to the usual result
+// of printf() for super simple logging.
//
//
// User defined format functions
@@ -86,6 +88,18 @@
// defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an
// example, see the implementation of printf() at the end of the source file.
//
+// Sometimes it's useful to be able to pass a list of format arguments through
+// to a non-template function. The FormatList class is provided as a way to do
+// this by storing the argument list in a type-opaque way. Continuing the
+// example from above, we construct a FormatList using makeFormatList():
+//
+// FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour, min);
+//
+// The format list can now be passed into any non-template function and used
+// via a call to the vformat() function:
+//
+// tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList);
+//
//
// Additional API information
// --------------------------
@@ -109,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.
@@ -118,6 +132,7 @@ namespace tfm = tinyformat;
//------------------------------------------------------------------------------
// Implementation details.
+#include <algorithm>
#include <cassert>
#include <iostream>
#include <sstream>
@@ -133,22 +148,29 @@ namespace tfm = tinyformat;
# endif
#endif
-#ifdef __GNUC__
-# define TINYFORMAT_NOINLINE __attribute__((noinline))
-#elif defined(_MSC_VER)
-# define TINYFORMAT_NOINLINE __declspec(noinline)
-#else
-# define TINYFORMAT_NOINLINE
-#endif
-
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201
// std::showpos is broken on old libstdc++ as provided with OSX. See
// http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html
# define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
#endif
+#ifdef __APPLE__
+// Workaround OSX linker warning: xcode uses different default symbol
+// visibilities for static libs vs executables (see issue #25)
+# define TINYFORMAT_HIDDEN __attribute__((visibility("hidden")))
+#else
+# define TINYFORMAT_HIDDEN
+#endif
+
namespace tinyformat {
+class format_error: public std::runtime_error
+{
+public:
+ format_error(const std::string &what): std::runtime_error(what) {
+ }
+};
+
//------------------------------------------------------------------------------
namespace detail {
@@ -247,6 +269,29 @@ struct convertToInt<T,true>
static int invoke(const T& value) { return static_cast<int>(value); }
};
+// Format at most ntrunc characters to the given stream.
+template<typename T>
+inline void formatTruncated(std::ostream& out, const T& value, int ntrunc)
+{
+ std::ostringstream tmp;
+ tmp << value;
+ std::string result = tmp.str();
+ out.write(result.c_str(), (std::min)(ntrunc, static_cast<int>(result.size())));
+}
+#define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type) \
+inline void formatTruncated(std::ostream& out, type* value, int ntrunc) \
+{ \
+ std::streamsize len = 0; \
+ while(len < ntrunc && value[len] != 0) \
+ ++len; \
+ out.write(value, len); \
+}
+// Overload for const char* and char*. Could overload for signed & unsigned
+// char too, but these are technically unneeded for printf compatibility.
+TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char)
+TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char)
+#undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR
+
} // namespace detail
@@ -255,18 +300,20 @@ struct convertToInt<T,true>
// desired.
-// Format a value into a stream. Called from format() for all types by default.
-//
-// Users may override this for their own types. When this function is called,
-// the stream flags will have been modified according to the format string.
-// The format specification is provided in the range [fmtBegin, fmtEnd).
-//
-// By default, formatValue() uses the usual stream insertion operator
-// operator<< to format the type T, with special cases for the %c and %p
-// conversions.
+/// Format a value into a stream, delegating to operator<< by default.
+///
+/// Users may override this for their own types. When this function is called,
+/// the stream flags will have been modified according to the format string.
+/// The format specification is provided in the range [fmtBegin, fmtEnd). For
+/// truncating conversions, ntrunc is set to the desired maximum number of
+/// characters, for example "%.7s" calls formatValue with ntrunc = 7.
+///
+/// By default, formatValue() uses the usual stream insertion operator
+/// operator<< to format the type T, with special cases for the %c and %p
+/// conversions.
template<typename T>
inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
- const char* fmtEnd, const T& value)
+ const char* fmtEnd, int ntrunc, const T& value)
{
#ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS
// Since we don't support printing of wchar_t using "%ls", make it fail at
@@ -288,6 +335,12 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
else if(detail::formatZeroIntegerWorkaround<T>::invoke(out, value)) /**/;
#endif
+ else if(ntrunc >= 0)
+ {
+ // Take care not to overread C strings in truncating conversions like
+ // "%.4s" where at most 4 characters may be read.
+ detail::formatTruncated(out, value, ntrunc);
+ }
else
out << value;
}
@@ -296,7 +349,7 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
// Overloaded version for char types to support printing as an integer
#define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \
inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, \
- const char* fmtEnd, charType value) \
+ const char* fmtEnd, int /**/, charType value) \
{ \
switch(*(fmtEnd-1)) \
{ \
@@ -435,225 +488,91 @@ cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' +
namespace detail {
-// Class holding current position in format string and an output stream into
-// which arguments are formatted.
-class FormatIterator
+// Type-opaque holder for an argument to format(), with associated actions on
+// the type held as explicit function pointers. This allows FormatArg's for
+// each argument to be allocated as a homogenous array inside FormatList
+// whereas a naive implementation based on inheritance does not.
+class FormatArg
{
public:
- // Flags for features not representable with standard stream state
- enum ExtraFormatFlags
- {
- Flag_None = 0,
- Flag_TruncateToPrecision = 1<<0, // truncate length to stream precision()
- Flag_SpacePadPositive = 1<<1, // pad positive values with spaces
- Flag_VariableWidth = 1<<2, // variable field width in arg list
- Flag_VariablePrecision = 1<<3 // variable field precision in arg list
- };
-
- // out is the output stream, fmt is the full format string
- FormatIterator(std::ostream& out, const char* fmt)
- : m_out(out),
- m_fmt(fmt),
- m_extraFlags(Flag_None),
- m_wantWidth(false),
- m_wantPrecision(false),
- m_variableWidth(0),
- m_variablePrecision(0),
- m_origWidth(out.width()),
- m_origPrecision(out.precision()),
- m_origFlags(out.flags()),
- m_origFill(out.fill())
+ FormatArg() {}
+
+ template<typename T>
+ FormatArg(const T& value)
+ : m_value(static_cast<const void*>(&value)),
+ m_formatImpl(&formatImpl<T>),
+ m_toIntImpl(&toIntImpl<T>)
{ }
- // Print remaining part of format string.
- void finish()
+ void format(std::ostream& out, const char* fmtBegin,
+ const char* fmtEnd, int ntrunc) const
{
- // It would be nice if we could do this from the destructor, but we
- // can't if TINFORMAT_ERROR is used to throw an exception!
- m_fmt = printFormatStringLiteral(m_out, m_fmt);
- if(*m_fmt != '\0')
- TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string");
+ m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);
}
- ~FormatIterator()
+ int toInt() const
{
- // Restore stream state
- m_out.width(m_origWidth);
- m_out.precision(m_origPrecision);
- m_out.flags(m_origFlags);
- m_out.fill(m_origFill);
+ return m_toIntImpl(m_value);
}
- template<typename T>
- void accept(const T& value);
-
private:
- // Parse and return an integer from the string c, as atoi()
- // On return, c is set to one past the end of the integer.
- static int parseIntAndAdvance(const char*& c)
+ template<typename T>
+ TINYFORMAT_HIDDEN static void formatImpl(std::ostream& out, const char* fmtBegin,
+ const char* fmtEnd, int ntrunc, const void* value)
{
- int i = 0;
- for(;*c >= '0' && *c <= '9'; ++c)
- i = 10*i + (*c - '0');
- return i;
+ formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast<const T*>(value));
}
- // Format at most truncLen characters of a C string to the given
- // stream. Return true if formatting proceeded (generic version always
- // returns false)
template<typename T>
- static bool formatCStringTruncate(std::ostream& /*out*/, const T& /*value*/,
- std::streamsize /*truncLen*/)
- {
- return false;
- }
-# define TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(type) \
- static bool formatCStringTruncate(std::ostream& out, type* value, \
- std::streamsize truncLen) \
- { \
- std::streamsize len = 0; \
- while(len < truncLen && value[len] != 0) \
- ++len; \
- out.write(value, len); \
- return true; \
- }
- // Overload for const char* and char*. Could overload for signed &
- // unsigned char too, but these are technically unneeded for printf
- // compatibility.
- TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(const char)
- TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(char)
-# undef TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE
-
- // Print literal part of format string and return next format spec
- // position.
- //
- // Skips over any occurrences of '%%', printing a literal '%' to the
- // output. The position of the first % character of the next
- // nontrivial format spec is returned, or the end of string.
- static const char* printFormatStringLiteral(std::ostream& out,
- const char* fmt)
+ TINYFORMAT_HIDDEN static int toIntImpl(const void* value)
{
- const char* c = fmt;
- for(; true; ++c)
- {
- switch(*c)
- {
- case '\0':
- out.write(fmt, static_cast<std::streamsize>(c - fmt));
- return c;
- case '%':
- out.write(fmt, static_cast<std::streamsize>(c - fmt));
- if(*(c+1) != '%')
- return c;
- // for "%%", tack trailing % onto next literal section.
- fmt = ++c;
- break;
- }
- }
+ return convertToInt<T>::invoke(*static_cast<const T*>(value));
}
- static const char* streamStateFromFormat(std::ostream& out,
- unsigned int& extraFlags,
- const char* fmtStart,
- int variableWidth,
- int variablePrecision);
-
- // Private copy & assign: Kill gcc warnings with -Weffc++
- FormatIterator(const FormatIterator&);
- FormatIterator& operator=(const FormatIterator&);
-
- // Stream, current format string & state
- std::ostream& m_out;
- const char* m_fmt;
- unsigned int m_extraFlags;
- // State machine info for handling of variable width & precision
- bool m_wantWidth;
- bool m_wantPrecision;
- int m_variableWidth;
- int m_variablePrecision;
- // Saved stream state
- std::streamsize m_origWidth;
- std::streamsize m_origPrecision;
- std::ios::fmtflags m_origFlags;
- char m_origFill;
+ const void* m_value;
+ void (*m_formatImpl)(std::ostream& out, const char* fmtBegin,
+ const char* fmtEnd, int ntrunc, const void* value);
+ int (*m_toIntImpl)(const void* value);
};
-// Accept a value for formatting into the internal stream.
-template<typename T>
-TINYFORMAT_NOINLINE // < greatly reduces bloat in optimized builds
-void FormatIterator::accept(const T& value)
+// Parse and return an integer from the string c, as atoi()
+// On return, c is set to one past the end of the integer.
+inline int parseIntAndAdvance(const char*& c)
{
- // Parse the format string
- const char* fmtEnd = 0;
- if(m_extraFlags == Flag_None && !m_wantWidth && !m_wantPrecision)
- {
- m_fmt = printFormatStringLiteral(m_out, m_fmt);
- fmtEnd = streamStateFromFormat(m_out, m_extraFlags, m_fmt, 0, 0);
- m_wantWidth = (m_extraFlags & Flag_VariableWidth) != 0;
- m_wantPrecision = (m_extraFlags & Flag_VariablePrecision) != 0;
- }
- // Consume value as variable width and precision specifier if necessary
- if(m_extraFlags & (Flag_VariableWidth | Flag_VariablePrecision))
- {
- if(m_wantWidth || m_wantPrecision)
- {
- int v = convertToInt<T>::invoke(value);
- if(m_wantWidth)
- {
- m_variableWidth = v;
- m_wantWidth = false;
- }
- else if(m_wantPrecision)
- {
- m_variablePrecision = v;
- m_wantPrecision = false;
- }
- return;
- }
- // If we get here, we've set both the variable precision and width as
- // required and we need to rerun the stream state setup to insert these.
- fmtEnd = streamStateFromFormat(m_out, m_extraFlags, m_fmt,
- m_variableWidth, m_variablePrecision);
- }
+ int i = 0;
+ for(;*c >= '0' && *c <= '9'; ++c)
+ i = 10*i + (*c - '0');
+ return i;
+}
- // Format the value into the stream.
- if(!(m_extraFlags & (Flag_SpacePadPositive | Flag_TruncateToPrecision)))
- formatValue(m_out, m_fmt, fmtEnd, value);
- else
+// Print literal part of format string and return next format spec
+// position.
+//
+// Skips over any occurrences of '%%', printing a literal '%' to the
+// output. The position of the first % character of the next
+// nontrivial format spec is returned, or the end of string.
+inline const char* printFormatStringLiteral(std::ostream& out, const char* fmt)
+{
+ const char* c = fmt;
+ for(;; ++c)
{
- // The following are special cases where there's no direct
- // correspondence between stream formatting and the printf() behaviour.
- // Instead, we simulate the behaviour crudely by formatting into a
- // temporary string stream and munging the resulting string.
- std::ostringstream tmpStream;
- tmpStream.copyfmt(m_out);
- if(m_extraFlags & Flag_SpacePadPositive)
- tmpStream.setf(std::ios::showpos);
- // formatCStringTruncate is required for truncating conversions like
- // "%.4s" where at most 4 characters of the c-string should be read.
- // If we didn't include this special case, we might read off the end.
- if(!( (m_extraFlags & Flag_TruncateToPrecision) &&
- formatCStringTruncate(tmpStream, value, m_out.precision()) ))
- {
- // Not a truncated c-string; just format normally.
- formatValue(tmpStream, m_fmt, fmtEnd, value);
- }
- std::string result = tmpStream.str(); // allocates... yuck.
- if(m_extraFlags & Flag_SpacePadPositive)
+ switch(*c)
{
- for(size_t i = 0, iend = result.size(); i < iend; ++i)
- if(result[i] == '+')
- result[i] = ' ';
+ case '\0':
+ out.write(fmt, c - fmt);
+ return c;
+ case '%':
+ out.write(fmt, c - fmt);
+ if(*(c+1) != '%')
+ return c;
+ // for "%%", tack trailing % onto next literal section.
+ fmt = ++c;
+ break;
+ default:
+ break;
}
- if((m_extraFlags & Flag_TruncateToPrecision) &&
- (int)result.size() > (int)m_out.precision())
- m_out.write(result.c_str(), m_out.precision());
- else
- m_out << result;
}
- m_extraFlags = Flag_None;
- m_fmt = fmtEnd;
}
@@ -663,13 +582,14 @@ void FormatIterator::accept(const T& value)
// with the form "%[flags][width][.precision][length]type".
//
// Formatting options which can't be natively represented using the ostream
-// state are returned in the extraFlags parameter which is a bitwise
-// combination of values from the ExtraFormatFlags enum.
-inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
- unsigned int& extraFlags,
- const char* fmtStart,
- int variableWidth,
- int variablePrecision)
+// state are returned in spacePadPositive (for space padded positive numbers)
+// and ntrunc (for truncating conversions). argIndex is incremented if
+// necessary to pull out variable width and precision . The function returns a
+// pointer to the character after the end of the current format spec.
+inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositive,
+ int& ntrunc, const char* fmtStart,
+ const detail::FormatArg* formatters,
+ int& argIndex, int numFormatters)
{
if(*fmtStart != '%')
{
@@ -684,9 +604,9 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
out.unsetf(std::ios::adjustfield | std::ios::basefield |
std::ios::floatfield | std::ios::showbase | std::ios::boolalpha |
std::ios::showpoint | std::ios::showpos | std::ios::uppercase);
- extraFlags = Flag_None;
bool precisionSet = false;
bool widthSet = false;
+ int widthExtra = 0;
const char* c = fmtStart + 1;
// 1) Parse flags
for(;; ++c)
@@ -713,12 +633,15 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
case ' ':
// overridden by show positive sign, '+' flag.
if(!(out.flags() & std::ios::showpos))
- extraFlags |= Flag_SpacePadPositive;
+ spacePadPositive = true;
continue;
case '+':
out.setf(std::ios::showpos);
- extraFlags &= ~Flag_SpacePadPositive;
+ spacePadPositive = false;
+ widthExtra = 1;
continue;
+ default:
+ break;
}
break;
}
@@ -731,15 +654,19 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
if(*c == '*')
{
widthSet = true;
- if(variableWidth < 0)
+ int width = 0;
+ if(argIndex < numFormatters)
+ width = formatters[argIndex++].toInt();
+ else
+ TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable width");
+ if(width < 0)
{
// negative widths correspond to '-' flag set
out.fill(' ');
out.setf(std::ios::left, std::ios::adjustfield);
- variableWidth = -variableWidth;
+ width = -width;
}
- out.width(variableWidth);
- extraFlags |= Flag_VariableWidth;
+ out.width(width);
++c;
}
// 3) Parse precision
@@ -750,8 +677,10 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
if(*c == '*')
{
++c;
- extraFlags |= Flag_VariablePrecision;
- precision = variablePrecision;
+ if(argIndex < numFormatters)
+ precision = formatters[argIndex++].toInt();
+ else
+ TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable precision");
}
else
{
@@ -814,7 +743,7 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
break;
case 's':
if(precisionSet)
- extraFlags |= Flag_TruncateToPrecision;
+ ntrunc = static_cast<int>(out.precision());
// Make %s print booleans as "true" and "false"
out.setf(std::ios::boolalpha);
break;
@@ -826,6 +755,8 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly "
"terminated by end of string");
return c;
+ default:
+ break;
}
if(intConversion && precisionSet && !widthSet)
{
@@ -833,7 +764,7 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
// padded with zeros on the left). This isn't really supported by the
// iostreams, but we can approximately simulate it with the width if
// the width isn't otherwise used.
- out.width(out.precision());
+ out.width(out.precision() + widthExtra);
out.setf(std::ios::internal, std::ios::adjustfield);
out.fill('0');
}
@@ -841,170 +772,282 @@ inline const char* FormatIterator::streamStateFromFormat(std::ostream& out,
}
-
//------------------------------------------------------------------------------
-// Private format function on top of which the public interface is implemented.
-// We enforce a mimimum of one value to be formatted to prevent bugs looking like
-//
-// const char* myStr = "100% broken";
-// printf(myStr); // Parses % as a format specifier
-#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
-
-template<typename T1>
-void format(FormatIterator& fmtIter, const T1& value1)
+inline void formatImpl(std::ostream& out, const char* fmt,
+ const detail::FormatArg* formatters,
+ int numFormatters)
{
- fmtIter.accept(value1);
- fmtIter.finish();
+ // Saved stream state
+ std::streamsize origWidth = out.width();
+ std::streamsize origPrecision = out.precision();
+ std::ios::fmtflags origFlags = out.flags();
+ char origFill = out.fill();
+
+ for (int argIndex = 0; argIndex < numFormatters; ++argIndex)
+ {
+ // Parse the format string
+ fmt = printFormatStringLiteral(out, fmt);
+ bool spacePadPositive = false;
+ int ntrunc = -1;
+ const char* fmtEnd = streamStateFromFormat(out, spacePadPositive, ntrunc, fmt,
+ formatters, argIndex, numFormatters);
+ if (argIndex >= numFormatters)
+ {
+ // Check args remain after reading any variable width/precision
+ TINYFORMAT_ERROR("tinyformat: Not enough format arguments");
+ return;
+ }
+ const FormatArg& arg = formatters[argIndex];
+ // Format the arg into the stream.
+ if(!spacePadPositive)
+ arg.format(out, fmt, fmtEnd, ntrunc);
+ else
+ {
+ // The following is a special case with no direct correspondence
+ // between stream formatting and the printf() behaviour. Simulate
+ // it crudely by formatting into a temporary string stream and
+ // munging the resulting string.
+ std::ostringstream tmpStream;
+ tmpStream.copyfmt(out);
+ tmpStream.setf(std::ios::showpos);
+ arg.format(tmpStream, fmt, fmtEnd, ntrunc);
+ std::string result = tmpStream.str(); // allocates... yuck.
+ for(size_t i = 0, iend = result.size(); i < iend; ++i)
+ if(result[i] == '+') result[i] = ' ';
+ out << result;
+ }
+ fmt = fmtEnd;
+ }
+
+ // Print remaining part of format string.
+ fmt = printFormatStringLiteral(out, fmt);
+ if(*fmt != '\0')
+ TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string");
+
+ // Restore stream state
+ out.width(origWidth);
+ out.precision(origPrecision);
+ out.flags(origFlags);
+ out.fill(origFill);
}
-// General version for C++11
-template<typename T1, typename... Args>
-void format(FormatIterator& fmtIter, const T1& value1, const Args&... args)
+} // namespace detail
+
+
+/// List of template arguments format(), held in a type-opaque way.
+///
+/// A const reference to FormatList (typedef'd as FormatListRef) may be
+/// conveniently used to pass arguments to non-template functions: All type
+/// information has been stripped from the arguments, leaving just enough of a
+/// common interface to perform formatting as required.
+class FormatList
{
- fmtIter.accept(value1);
- format(fmtIter, args...);
-}
+ public:
+ FormatList(detail::FormatArg* formatters, int N)
+ : m_formatters(formatters), m_N(N) { }
-#else
+ friend void vformat(std::ostream& out, const char* fmt,
+ const FormatList& list);
-inline void format(FormatIterator& fmtIter)
+ private:
+ const detail::FormatArg* m_formatters;
+ int m_N;
+};
+
+/// Reference to type-opaque format list for passing to vformat()
+typedef const FormatList& FormatListRef;
+
+
+namespace detail {
+
+// Format list subclass with fixed storage to avoid dynamic allocation
+template<int N>
+class FormatListN : public FormatList
{
- fmtIter.finish();
-}
+ public:
+#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
+ template<typename... Args>
+ FormatListN(const Args&... args)
+ : FormatList(&m_formatterStore[0], N),
+ m_formatterStore { FormatArg(args)... }
+ { static_assert(sizeof...(args) == N, "Number of args must be N"); }
+#else // C++98 version
+ void init(int) {}
+# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \
+ \
+ template<TINYFORMAT_ARGTYPES(n)> \
+ FormatListN(TINYFORMAT_VARARGS(n)) \
+ : FormatList(&m_formatterStore[0], n) \
+ { assert(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \
+ \
+ template<TINYFORMAT_ARGTYPES(n)> \
+ void init(int i, TINYFORMAT_VARARGS(n)) \
+ { \
+ m_formatterStore[i] = FormatArg(v1); \
+ init(i+1 TINYFORMAT_PASSARGS_TAIL(n)); \
+ }
-// General version for C++98
-#define TINYFORMAT_MAKE_FORMAT_DETAIL(n) \
-template<TINYFORMAT_ARGTYPES(n)> \
-void format(detail::FormatIterator& fmtIter, TINYFORMAT_VARARGS(n)) \
-{ \
- fmtIter.accept(v1); \
- format(fmtIter TINYFORMAT_PASSARGS_TAIL(n)); \
-}
+ TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR)
+# undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR
+#endif
-TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_DETAIL)
-#undef TINYFORMAT_MAKE_FORMAT_DETAIL
+ private:
+ FormatArg m_formatterStore[N];
+};
-#endif // End C++98 variadic template emulation for format()
+// Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard
+template<> class FormatListN<0> : public FormatList
+{
+ public: FormatListN() : FormatList(0, 0) {}
+};
} // namespace detail
//------------------------------------------------------------------------------
-// Implement all the main interface functions here in terms of detail::format()
+// Primary API functions
#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
-// C++11 - the simple case
-template<typename T1, typename... Args>
-void format(std::ostream& out, const char* fmt, const T1& v1, const Args&... args)
+/// Make type-agnostic format list from list of template arguments.
+///
+/// The exact return type of this function is an implementation detail and
+/// shouldn't be relied upon. Instead it should be stored as a FormatListRef:
+///
+/// FormatListRef formatList = makeFormatList( /*...*/ );
+template<typename... Args>
+detail::FormatListN<sizeof...(Args)> makeFormatList(const Args&... args)
+{
+ return detail::FormatListN<sizeof...(args)>(args...);
+}
+
+#else // C++98 version
+
+inline detail::FormatListN<0> makeFormatList()
{
- detail::FormatIterator fmtIter(out, fmt);
- format(fmtIter, v1, args...);
+ return detail::FormatListN<0>();
+}
+#define TINYFORMAT_MAKE_MAKEFORMATLIST(n) \
+template<TINYFORMAT_ARGTYPES(n)> \
+detail::FormatListN<n> makeFormatList(TINYFORMAT_VARARGS(n)) \
+{ \
+ return detail::FormatListN<n>(TINYFORMAT_PASSARGS(n)); \
}
+TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST)
+#undef TINYFORMAT_MAKE_MAKEFORMATLIST
+
+#endif
-template<typename T1, typename... Args>
-std::string format(const char* fmt, const T1& v1, const Args&... args)
+/// Format list of arguments to the stream according to the given format string.
+///
+/// The name vformat() is chosen for the semantic similarity to vprintf(): the
+/// list of format arguments is held in a single function argument.
+inline void vformat(std::ostream& out, const char* fmt, FormatListRef list)
+{
+ detail::formatImpl(out, fmt, list.m_formatters, list.m_N);
+}
+
+
+#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
+
+/// Format list of arguments to the stream according to given format string.
+template<typename... Args>
+void format(std::ostream& out, const char* fmt, const Args&... args)
+{
+ vformat(out, fmt, makeFormatList(args...));
+}
+
+/// Format list of arguments according to the given format string and return
+/// the result as a string.
+template<typename... Args>
+std::string format(const char* fmt, const Args&... args)
{
std::ostringstream oss;
- format(oss, fmt, v1, args...);
+ format(oss, fmt, args...);
return oss.str();
}
-template<typename T1, typename... Args>
-std::string format(const std::string &fmt, const T1& v1, const Args&... args)
+/// Format list of arguments to std::cout, according to the given format string
+template<typename... Args>
+void printf(const char* fmt, const Args&... args)
+{
+ format(std::cout, fmt, args...);
+}
+
+template<typename... Args>
+void printfln(const char* fmt, const Args&... args)
+{
+ format(std::cout, fmt, args...);
+ std::cout << '\n';
+}
+
+#else // C++98 version
+
+inline void format(std::ostream& out, const char* fmt)
+{
+ vformat(out, fmt, makeFormatList());
+}
+
+inline std::string format(const char* fmt)
{
std::ostringstream oss;
- format(oss, fmt.c_str(), v1, args...);
+ format(oss, fmt);
return oss.str();
}
-template<typename T1, typename... Args>
-void printf(const char* fmt, const T1& v1, const Args&... args)
+inline void printf(const char* fmt)
{
- format(std::cout, fmt, v1, args...);
+ format(std::cout, fmt);
}
-#else
+inline void printfln(const char* fmt)
+{
+ format(std::cout, fmt);
+ std::cout << '\n';
+}
-// C++98 - define the interface functions using the wrapping macros
#define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \
\
template<TINYFORMAT_ARGTYPES(n)> \
void format(std::ostream& out, const char* fmt, TINYFORMAT_VARARGS(n)) \
{ \
- tinyformat::detail::FormatIterator fmtIter(out, fmt); \
- tinyformat::detail::format(fmtIter, TINYFORMAT_PASSARGS(n)); \
+ vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n))); \
} \
\
template<TINYFORMAT_ARGTYPES(n)> \
std::string format(const char* fmt, TINYFORMAT_VARARGS(n)) \
{ \
std::ostringstream oss; \
- tinyformat::format(oss, fmt, TINYFORMAT_PASSARGS(n)); \
+ format(oss, fmt, TINYFORMAT_PASSARGS(n)); \
return oss.str(); \
} \
\
template<TINYFORMAT_ARGTYPES(n)> \
-std::string format(const std::string &fmt, TINYFORMAT_VARARGS(n)) \
+void printf(const char* fmt, TINYFORMAT_VARARGS(n)) \
{ \
- std::ostringstream oss; \
- tinyformat::format(oss, fmt.c_str(), TINYFORMAT_PASSARGS(n)); \
- return oss.str(); \
+ format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \
} \
\
template<TINYFORMAT_ARGTYPES(n)> \
-void printf(const char* fmt, TINYFORMAT_VARARGS(n)) \
+void printfln(const char* fmt, TINYFORMAT_VARARGS(n)) \
{ \
- tinyformat::format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \
+ format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \
+ std::cout << '\n'; \
}
TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS)
#undef TINYFORMAT_MAKE_FORMAT_FUNCS
-#endif
-
-//------------------------------------------------------------------------------
-// Define deprecated wrapping macro for backward compatibility in tinyformat
-// 1.x. Will be removed in version 2!
-#define TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS
-#define TINYFORMAT_WRAP_FORMAT_N(n, returnType, funcName, funcDeclSuffix, \
- bodyPrefix, streamName, bodySuffix) \
-template<TINYFORMAT_ARGTYPES(n)> \
-returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt, \
- TINYFORMAT_VARARGS(n)) funcDeclSuffix \
-{ \
- bodyPrefix \
- tinyformat::format(streamName, fmt, TINYFORMAT_PASSARGS(n)); \
- bodySuffix \
-} \
-
-#define TINYFORMAT_WRAP_FORMAT(returnType, funcName, funcDeclSuffix, \
- bodyPrefix, streamName, bodySuffix) \
-inline \
-returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \
- ) funcDeclSuffix \
-{ \
- bodyPrefix \
- tinyformat::detail::FormatIterator(streamName, fmt).finish(); \
- bodySuffix \
-} \
-TINYFORMAT_WRAP_FORMAT_N(1 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(2 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(3 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(4 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(5 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(6 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(7 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(8 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(9 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(10, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(11, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(12, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(13, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(14, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(15, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
-TINYFORMAT_WRAP_FORMAT_N(16, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \
+#endif
+// Added for Bitcoin Core
+template<typename... Args>
+std::string format(const std::string &fmt, const Args&... args)
+{
+ std::ostringstream oss;
+ format(oss, fmt.c_str(), args...);
+ return oss.str();
+}
} // namespace tinyformat
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 0d6b655675..c1bd95b00f 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -1,9 +1,10 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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 "torcontrol.h"
#include "utilstrencodings.h"
+#include "netbase.h"
#include "net.h"
#include "util.h"
#include "crypto/hmac_sha256.h"
@@ -121,8 +122,8 @@ private:
static void eventcb(struct bufferevent *bev, short what, void *ctx);
};
-TorControlConnection::TorControlConnection(struct event_base *base):
- base(base), b_conn(0)
+TorControlConnection::TorControlConnection(struct event_base *_base):
+ base(_base), b_conn(0)
{
}
@@ -162,7 +163,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();
@@ -181,19 +182,20 @@ 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);
}
}
-bool TorControlConnection::Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected)
+bool TorControlConnection::Connect(const std::string &target, const ConnectionCB& _connected, const ConnectionCB& _disconnected)
{
if (b_conn)
Disconnect();
@@ -212,8 +214,8 @@ bool TorControlConnection::Connect(const std::string &target, const ConnectionCB
return false;
bufferevent_setcb(b_conn, TorControlConnection::readcb, NULL, TorControlConnection::eventcb, this);
bufferevent_enable(b_conn, EV_READ|EV_WRITE);
- this->connected = connected;
- this->disconnected = disconnected;
+ this->connected = _connected;
+ this->disconnected = _disconnected;
// Finally, connect to target
if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) {
@@ -312,9 +314,9 @@ 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");
+ FILE *f = fsbridge::fopen(filename, "rb");
if (f == NULL)
return std::make_pair(false,"");
std::string retval;
@@ -332,9 +334,9 @@ 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");
+ FILE *f = fsbridge::fopen(filename, "wb");
if (f == NULL)
return false;
if (fwrite(data.data(), 1, data.size(), f) != data.size()) {
@@ -357,7 +359,7 @@ public:
~TorController();
/** Get name fo file to store private key in */
- std::string GetPrivateKeyFile();
+ fs::path GetPrivateKeyFile();
/** Reconnect, after getting disconnected */
void Reconnect();
@@ -371,7 +373,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;
@@ -393,23 +395,23 @@ private:
static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
};
-TorController::TorController(struct event_base* baseIn, const std::string& target):
- base(baseIn),
- target(target), conn(base), reconnect(true), reconnect_ev(0),
+TorController::TorController(struct event_base* _base, const std::string& _target):
+ base(_base),
+ target(_target), conn(base), reconnect(true), reconnect_ev(0),
reconnect_timeout(RECONNECT_TIMEOUT_START)
{
reconnect_ev = event_new(base, -1, 0, reconnect_cb, this);
if (!reconnect_ev)
LogPrintf("tor: Failed to create event for reconnection: out of memory?\n");
// Start connection attempts immediately
- if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1),
+ if (!conn.Connect(_target, boost::bind(&TorController::connected_cb, this, _1),
boost::bind(&TorController::disconnected_cb, this, _1) )) {
- LogPrintf("tor: Initiating connection to Tor control port %s failed\n", target);
+ LogPrintf("tor: Initiating connection to Tor control port %s failed\n", _target);
}
// 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;
}
}
@@ -425,10 +427,10 @@ TorController::~TorController()
}
}
-void TorController::add_onion_cb(TorControlConnection& conn, const TorControlReply& reply)
+void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlReply& reply)
{
if (reply.code == 250) {
- LogPrint("tor", "tor: ADD_ONION successful\n");
+ LogPrint(BCLog::TOR, "tor: ADD_ONION successful\n");
BOOST_FOREACH(const std::string &s, reply.lines) {
std::map<std::string,std::string> m = ParseTorReplyMapping(s);
std::map<std::string,std::string>::iterator i;
@@ -437,13 +439,12 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep
if ((i = m.find("PrivateKey")) != m.end())
private_key = i->second;
}
-
- service = CService(service_id+".onion", GetListenPort());
+ 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
@@ -454,26 +455,27 @@ void TorController::add_onion_cb(TorControlConnection& conn, const TorControlRep
}
}
-void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& reply)
+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", "") == "") {
- proxyType addrOnion = proxyType(CService("127.0.0.1", 9050), true);
+ CService resolved(LookupNumeric("127.0.0.1", 9050));
+ proxyType addrOnion = proxyType(resolved, true);
SetProxy(NET_TOR, addrOnion);
SetLimited(NET_TOR, false);
}
// Finally - now create the service
if (private_key.empty()) // No private key, generate one
- private_key = "NEW:BEST";
+ private_key = "NEW:RSA1024"; // Explicitly request RSA1024 - see issue #9214
// Request hidden service, redirect port.
// Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient
// choice. TODO; refactor the shutdown sequence some day.
- conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()),
+ _conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()),
boost::bind(&TorController::add_onion_cb, this, _1, _2));
} else {
LogPrintf("tor: Authentication failed\n");
@@ -500,23 +502,23 @@ static std::vector<uint8_t> ComputeResponse(const std::string &key, const std::v
{
CHMAC_SHA256 computeHash((const uint8_t*)key.data(), key.size());
std::vector<uint8_t> computedHash(CHMAC_SHA256::OUTPUT_SIZE, 0);
- computeHash.Write(begin_ptr(cookie), cookie.size());
- computeHash.Write(begin_ptr(clientNonce), clientNonce.size());
- computeHash.Write(begin_ptr(serverNonce), serverNonce.size());
- computeHash.Finalize(begin_ptr(computedHash));
+ computeHash.Write(cookie.data(), cookie.size());
+ computeHash.Write(clientNonce.data(), clientNonce.size());
+ computeHash.Write(serverNonce.data(), serverNonce.size());
+ computeHash.Finalize(computedHash.data());
return computedHash;
}
-void TorController::authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply)
+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);
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;
@@ -529,7 +531,7 @@ void TorController::authchallenge_cb(TorControlConnection& conn, const TorContro
}
std::vector<uint8_t> computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce);
- conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2));
+ _conn.Command("AUTHENTICATE " + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2));
} else {
LogPrintf("tor: Invalid reply to AUTHCHALLENGE\n");
}
@@ -538,7 +540,7 @@ void TorController::authchallenge_cb(TorControlConnection& conn, const TorContro
}
}
-void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply)
+void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorControlReply& reply)
{
if (reply.code == 250) {
std::set<std::string> methods;
@@ -561,12 +563,12 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl
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);
+ LogPrint(BCLog::TOR, "tor: Supported authentication method: %s\n", s);
}
// Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD
/* Authentication:
@@ -576,25 +578,25 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl
std::string torpassword = 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));
+ _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");
- conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2));
+ 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));
+ // _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);
- conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2));
+ _conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2));
} else {
if (status_cookie.first) {
LogPrintf("tor: Authentication cookie %s is not exactly %i bytes, as is required by the spec\n", cookiefile, TOR_COOKIE_SIZE);
@@ -612,15 +614,15 @@ void TorController::protocolinfo_cb(TorControlConnection& conn, const TorControl
}
}
-void TorController::connected_cb(TorControlConnection& conn)
+void TorController::connected_cb(TorControlConnection& _conn)
{
reconnect_timeout = RECONNECT_TIMEOUT_START;
// First send a PROTOCOLINFO command to figure out what authentication is expected
- if (!conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2)))
+ if (!_conn.Command("PROTOCOLINFO 1", boost::bind(&TorController::protocolinfo_cb, this, _1, _2)))
LogPrintf("tor: Error sending initial protocolinfo command\n");
}
-void TorController::disconnected_cb(TorControlConnection& conn)
+void TorController::disconnected_cb(TorControlConnection& _conn)
{
// Stop advertising service when disconnected
if (service.IsValid())
@@ -629,7 +631,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));
@@ -649,9 +651,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)
@@ -661,26 +663,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, 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;
}
@@ -690,18 +692,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 = 0;
}
}
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 078c29def3..a3889fdf79 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -14,8 +14,6 @@
#include <boost/thread.hpp>
-using namespace std;
-
static const char DB_COINS = 'c';
static const char DB_BLOCK_FILES = 'f';
static const char DB_TXINDEX = 't';
@@ -32,11 +30,11 @@ CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(Get
}
bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
- return db.Read(make_pair(DB_COINS, txid), coins);
+ return db.Read(std::make_pair(DB_COINS, txid), coins);
}
bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
- return db.Exists(make_pair(DB_COINS, txid));
+ return db.Exists(std::make_pair(DB_COINS, txid));
}
uint256 CCoinsViewDB::GetBestBlock() const {
@@ -53,9 +51,9 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
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));
+ batch.Erase(std::make_pair(DB_COINS, it->first));
else
- batch.Write(make_pair(DB_COINS, it->first), it->second.coins);
+ batch.Write(std::make_pair(DB_COINS, it->first), it->second.coins);
changed++;
}
count++;
@@ -65,7 +63,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
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);
+ LogPrint(BCLog::COINDB, "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
return db.WriteBatch(batch);
}
@@ -73,7 +71,7 @@ CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWra
}
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) {
@@ -139,23 +137,23 @@ void CCoinsViewDBCursor::Next()
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);
}
@@ -173,9 +171,9 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex)
{
- boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
+ 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()) {
diff --git a/src/txdb.h b/src/txdb.h
index 5b98d2792c..d9214ba618 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -21,8 +21,14 @@ class CBlockIndex;
class CCoinsViewDBCursor;
class uint256;
+//! Compensate for extra memory peak (x1.5-x1.9) at flush time.
+static constexpr int DB_PEAK_USAGE_FACTOR = 2;
+//! No need to periodic flush if at least this much space still available.
+static constexpr int MAX_BLOCK_COINSDB_USAGE = 200 * DB_PEAK_USAGE_FACTOR;
+//! Always periodic flush if less than this much space still available.
+static constexpr int MIN_BLOCK_COINSDB_USAGE = 50 * DB_PEAK_USAGE_FACTOR;
//! -dbcache default (MiB)
-static const int64_t nDefaultDbCache = 300;
+static const int64_t nDefaultDbCache = 450;
//! max. -dbcache (MiB)
static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024;
//! min. -dbcache (MiB)
@@ -43,7 +49,7 @@ struct CDiskTxPos : public CDiskBlockPos
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CDiskBlockPos*)this);
READWRITE(VARINT(nTxOffset));
}
@@ -92,7 +98,7 @@ public:
private:
CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256 &hashBlockIn):
CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
- boost::scoped_ptr<CDBIterator> pcursor;
+ std::unique_ptr<CDBIterator> pcursor;
std::pair<char, uint256> keyTmp;
friend class CCoinsViewDB;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index a48a6d9465..ac842da6bf 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -1,14 +1,13 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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 "txmempool.h"
-#include "clientversion.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
-#include "main.h"
+#include "validation.h"
#include "policy/policy.h"
#include "policy/fees.h"
#include "streams.h"
@@ -16,27 +15,19 @@
#include "util.h"
#include "utilmoneystr.h"
#include "utiltime.h"
-#include "version.h"
-using namespace std;
-
-CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
- int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
- bool poolHasNoInputsOf, CAmount _inChainInputValue,
+CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
+ int64_t _nTime, unsigned int _entryHeight,
bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp):
- tx(std::make_shared<CTransaction>(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
- hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue),
+ tx(_tx), nFee(_nFee), nTime(_nTime), entryHeight(_entryHeight),
spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp)
{
- nTxCost = GetTransactionCost(_tx);
- nModSize = _tx.CalculateModifiedSize(GetTxSize());
+ nTxWeight = GetTransactionWeight(*tx);
nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx);
nCountWithDescendants = 1;
nSizeWithDescendants = GetTxSize();
nModFeesWithDescendants = nFee;
- CAmount nValueIn = _tx.GetValueOut()+nFee;
- assert(inChainInputValue <= nValueIn);
feeDelta = 0;
@@ -51,16 +42,6 @@ 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;
@@ -75,7 +56,7 @@ void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp)
size_t CTxMemPoolEntry::GetTxSize() const
{
- return GetVirtualTransactionSize(nTxCost);
+ return GetVirtualTransactionSize(nTxWeight, sigOpCost);
}
// Update the given tx for any in-mempool descendants.
@@ -125,7 +106,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)
@@ -173,6 +154,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();
@@ -348,8 +331,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,14 +340,6 @@ 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);
- minReasonableRelayFee = _minReasonableRelayFee;
-}
-
-CTxMemPool::~CTxMemPool()
-{
- delete minerPolicyEstimator;
}
void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
@@ -392,10 +367,11 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n)
nTransactionsUpdated += n;
}
-bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate)
+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;
@@ -404,11 +380,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));
}
}
@@ -442,16 +418,17 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
nTransactionsUpdated++;
totalTxSize += entry.GetTxSize();
- minerPolicyEstimator->processTransaction(entry, fCurrentEstimate);
+ if (minerPolicyEstimator) {minerPolicyEstimator->processTransaction(entry, validFeeEstimate);}
- vTxHashes.emplace_back(hash, newit);
+ vTxHashes.emplace_back(tx.GetWitnessHash(), newit);
newit->vTxHashesIdx = vTxHashes.size() - 1;
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)
mapNextTx.erase(txin.prevout);
@@ -471,7 +448,7 @@ void CTxMemPool::removeUnchecked(txiter it)
mapLinks.erase(it);
mapTx.erase(it);
nTransactionsUpdated++;
- minerPolicyEstimator->removeTx(hash);
+ if (minerPolicyEstimator) {minerPolicyEstimator->removeTx(hash);}
}
// Calculates descendants of entry that are not already in setDescendants, and adds to
@@ -503,7 +480,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants
}
}
-void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list<CTransaction>& removed)
+void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReason reason)
{
// Remove transaction from memory pool
{
@@ -530,10 +507,8 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list<CTransact
BOOST_FOREACH(txiter it, txToRemove) {
CalculateDescendants(it, setAllRemoves);
}
- BOOST_FOREACH(txiter it, setAllRemoves) {
- removed.push_back(it->GetTx());
- }
- RemoveStaged(setAllRemoves, false);
+
+ RemoveStaged(setAllRemoves, false, reason);
}
}
@@ -541,7 +516,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
{
// Remove transactions spending a coinbase which are now immature and no-longer-final transactions
LOCK(cs);
- list<CTransaction> transactionsToRemove;
+ setEntries txToRemove;
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
const CTransaction& tx = it->GetTx();
LockPoints lp = it->GetLockPoints();
@@ -549,16 +524,16 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) {
// Note if CheckSequenceLocks fails the LockPoints may still be invalid
// So it's critical that we remove the tx and not depend on the LockPoints.
- transactionsToRemove.push_back(tx);
+ txToRemove.insert(it);
} else if (it->GetSpendsCoinbase()) {
BOOST_FOREACH(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 (nCheckFrequency != 0) assert(coins);
if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) {
- transactionsToRemove.push_back(tx);
+ txToRemove.insert(it);
break;
}
}
@@ -567,16 +542,16 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
mapTx.modify(it, update_lock_points(lp));
}
}
- BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) {
- list<CTransaction> removed;
- removeRecursive(tx, removed);
+ setEntries setAllRemoves;
+ for (txiter it : txToRemove) {
+ CalculateDescendants(it, setAllRemoves);
}
+ RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG);
}
-void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed)
+void CTxMemPool::removeConflicts(const CTransaction &tx)
{
// Remove transactions which depend on inputs of tx, recursively
- list<CTransaction> result;
LOCK(cs);
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
auto it = mapNextTx.find(txin.prevout);
@@ -584,8 +559,8 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>
const CTransaction &txConflict = *it->second;
if (txConflict != tx)
{
- removeRecursive(txConflict, removed);
ClearPrioritisation(txConflict.GetHash());
+ removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT);
}
}
}
@@ -594,32 +569,31 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>
/**
* Called when a block is connected. Removes from mempool and updates the miner fee estimator.
*/
-void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
- std::list<CTransaction>& conflicts, bool fCurrentEstimate)
+void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight)
{
LOCK(cs);
- std::vector<CTxMemPoolEntry> entries;
- BOOST_FOREACH(const CTransaction& tx, vtx)
+ std::vector<const CTxMemPoolEntry*> entries;
+ for (const auto& tx : vtx)
{
- uint256 hash = tx.GetHash();
+ uint256 hash = tx->GetHash();
indexed_transaction_set::iterator i = mapTx.find(hash);
if (i != mapTx.end())
- entries.push_back(*i);
+ entries.push_back(&*i);
}
- BOOST_FOREACH(const CTransaction& tx, vtx)
+ // Before the txs in the new block have been removed from the mempool, update policy estimates
+ if (minerPolicyEstimator) {minerPolicyEstimator->processBlock(nBlockHeight, entries);}
+ for (const auto& tx : vtx)
{
- txiter it = mapTx.find(tx.GetHash());
+ 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, conflicts);
- ClearPrioritisation(tx.GetHash());
+ removeConflicts(*tx);
+ ClearPrioritisation(tx->GetHash());
}
- // After the txs in the new block have been removed from the mempool, update policy estimates
- minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate);
lastRollingFeeUpdate = GetTime();
blockSinceLastRollingFeeBump = true;
}
@@ -648,18 +622,19 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
if (nCheckFrequency == 0)
return;
- if (insecure_rand() >= nCheckFrequency)
+ 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;
CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins));
+ 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();
@@ -737,7 +712,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
waitingOnDependants.push_back(&(*it));
else {
CValidationState state;
- assert(CheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL));
+ bool fCheckResult = tx.IsCoinBase() ||
+ Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight);
+ assert(fCheckResult);
UpdateCoins(tx, mempoolDuplicate, 1000000);
}
}
@@ -751,7 +728,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
stepsSinceLastRemove++;
assert(stepsSinceLastRemove < waitingOnDependants.size());
} else {
- assert(CheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, NULL));
+ bool fCheckResult = entry->GetTx().IsCoinBase() ||
+ Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight);
+ assert(fCheckResult);
UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000);
stepsSinceLastRemove = 0;
}
@@ -813,7 +792,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();
@@ -826,6 +805,10 @@ void CTxMemPool::queryHashes(vector<uint256>& vtxid)
}
}
+static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) {
+ return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize()), it->GetModifiedFee() - it->GetFee()};
+}
+
std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
{
LOCK(cs);
@@ -834,13 +817,13 @@ std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
std::vector<TxMempoolInfo> ret;
ret.reserve(mapTx.size());
for (auto it : iters) {
- ret.push_back(TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize())});
+ ret.push_back(GetInfo(it));
}
return ret;
}
-std::shared_ptr<const CTransaction> CTxMemPool::get(const uint256& hash) const
+CTransactionRef CTxMemPool::get(const uint256& hash) const
{
LOCK(cs);
indexed_transaction_set::const_iterator i = mapTx.find(hash);
@@ -855,75 +838,18 @@ TxMempoolInfo CTxMemPool::info(const uint256& hash) const
indexed_transaction_set::const_iterator i = mapTx.find(hash);
if (i == mapTx.end())
return TxMempoolInfo();
- return TxMempoolInfo{i->GetSharedTx(), i->GetTime(), CFeeRate(i->GetFee(), i->GetTxSize())};
-}
-
-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);
+ return GetInfo(i);
}
-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 << 109900; // version required to read: 0.10.99 or later
- fileout << CLIENT_VERSION; // version that wrote the file
- minerPolicyEstimator->Write(fileout);
- }
- catch (const std::exception&) {
- LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)\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);
- }
- 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();
@@ -932,20 +858,26 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash,
BOOST_FOREACH(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);
+ BOOST_FOREACH(txiter descendantIt, setDescendants) {
+ mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0));
+ }
}
}
- 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)
@@ -968,7 +900,7 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) 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.
- shared_ptr<const CTransaction> ptx = mempool.get(txid);
+ CTransactionRef ptx = mempool.get(txid);
if (ptx) {
coins = CCoins(*ptx, MEMPOOL_HEIGHT);
return true;
@@ -986,11 +918,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);
+ removeUnchecked(it, reason);
}
}
@@ -1006,18 +938,18 @@ int CTxMemPool::Expire(int64_t time) {
BOOST_FOREACH(txiter removeit, toremove) {
CalculateDescendants(removeit, stage);
}
- RemoveStaged(stage, false);
+ RemoveStaged(stage, false, MemPoolRemovalReason::EXPIRY);
return stage.size();
}
-bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate)
+bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool validFeeEstimate)
{
LOCK(cs);
setEntries setAncestors;
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
std::string dummy;
CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);
- return addUnchecked(hash, entry, setAncestors, fCurrentEstimate);
+ return addUnchecked(hash, entry, setAncestors, validFeeEstimate);
}
void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add)
@@ -1072,12 +1004,12 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);
lastRollingFeeUpdate = time;
- if (rollingMinimumFeeRate < minReasonableRelayFee.GetFeePerK() / 2) {
+ if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() / 2) {
rollingMinimumFeeRate = 0;
return CFeeRate(0);
}
}
- return std::max(CFeeRate(rollingMinimumFeeRate), minReasonableRelayFee);
+ return std::max(CFeeRate(rollingMinimumFeeRate), incrementalRelayFee);
}
void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
@@ -1101,7 +1033,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
// to have 0 fee). This way, we don't allow txn to enter mempool with feerate
// equal to txn which were removed with no block in between.
CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());
- removed += minReasonableRelayFee;
+ removed += incrementalRelayFee;
trackPackageRemoved(removed);
maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);
@@ -1112,23 +1044,31 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
std::vector<CTransaction> txn;
if (pvNoSpendsRemaining) {
txn.reserve(stage.size());
- BOOST_FOREACH(txiter it, stage)
- txn.push_back(it->GetTx());
+ BOOST_FOREACH(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 it = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0));
- if (it == mapNextTx.end() || it->first->hash != txin.prevout.hash)
+ 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);
}
}
}
}
- 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 {
+ LOCK(cs);
+ auto it = mapTx.find(txid);
+ return it == mapTx.end() || (it->GetCountWithAncestors() < chainLimit &&
+ it->GetCountWithDescendants() < chainLimit);
}
diff --git a/src/txmempool.h b/src/txmempool.h
index e5a500e19d..9cb73fcc0c 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -1,41 +1,35 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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_TXMEMPOOL_H
#define BITCOIN_TXMEMPOOL_H
-#include <list>
#include <memory>
#include <set>
+#include <map>
+#include <vector>
+#include <utility>
+#include <string>
#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/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;
@@ -58,7 +52,7 @@ class CTxMemPool;
/** \class CTxMemPoolEntry
*
- * CTxMemPoolEntry stores data about the correponding transaction, as well
+ * CTxMemPoolEntry stores data about the corresponding transaction, as well
* as data about all in-mempool transactions that depend on the transaction
* ("descendant" transactions).
*
@@ -66,26 +60,17 @@ 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
{
private:
- std::shared_ptr<const CTransaction> tx;
+ CTransactionRef tx;
CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
- size_t nTxCost; //!< ... and avoid recomputing tx cost (also used for GetTxSize())
- size_t nModSize; //!< ... and modified size for priority
+ size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize())
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
- bool hadNoDependencies; //!< Not dependent on any other txs when it entered the mempool
- CAmount inChainInputValue; //!< Sum of all txin values that are already in blockchain
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
@@ -93,9 +78,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)
@@ -107,31 +90,26 @@ private:
int64_t nSigOpCostWithAncestors;
public:
- CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
- int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
- bool poolHasNoInputsOf, CAmount _inChainInputValue, bool spendsCoinbase,
+ CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
+ int64_t _nTime, unsigned int _entryHeight,
+ bool spendsCoinbase,
int64_t nSigOpsCost, LockPoints lp);
+
CTxMemPoolEntry(const CTxMemPoolEntry& other);
const CTransaction& GetTx() const { return *this->tx; }
- std::shared_ptr<const CTransaction> 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;
+ CTransactionRef GetSharedTx() const { return this->tx; }
const CAmount& GetFee() const { return nFee; }
size_t GetTxSize() const;
- size_t GetTxCost() const { return nTxCost; }
+ size_t GetTxWeight() const { return nTxWeight; }
int64_t GetTime() const { return nTime; }
unsigned int GetHeight() const { return entryHeight; }
- bool WasClearAtEntry() const { return hadNoDependencies; }
int64_t GetSigOpCost() const { return sigOpCost; }
int64_t GetModifiedFee() const { return nFee + feeDelta; }
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);
@@ -318,24 +296,43 @@ class CBlockPolicyEstimator;
struct TxMempoolInfo
{
/** The transaction itself */
- std::shared_ptr<const CTransaction> tx;
+ CTransactionRef tx;
/** Time the transaction entered the mempool. */
int64_t nTime;
/** Feerate of the transaction. */
CFeeRate feeRate;
+
+ /** The fee delta. */
+ 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
};
/**
- * CTxMemPool stores valid-according-to-the-current-best-chain
- * transactions that may be included in the next block.
+ * CTxMemPool stores valid-according-to-the-current-best-chain transactions
+ * that may be included in the next block.
*
- * 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: if a new transaction double-spends
- * an input of a transaction in the pool, it is dropped,
- * as are non-standard transactions.
+ * 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 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.
+ * - a non-standard transaction.
*
* CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping:
*
@@ -395,14 +392,6 @@ 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
{
@@ -411,11 +400,9 @@ private:
unsigned int nTransactionsUpdated;
CBlockPolicyEstimator* minerPolicyEstimator;
- uint64_t totalTxSize; //!< sum of all mempool tx' byte sizes
+ 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.
uint64_t cachedInnerUsage; //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves)
- CFeeRate minReasonableRelayFee;
-
mutable int64_t lastRollingFeeUpdate;
mutable bool blockSinceLastRollingFeeBump;
mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially
@@ -462,7 +449,7 @@ public:
indexed_transaction_set mapTx;
typedef indexed_transaction_set::nth_index<0>::type::iterator txiter;
- std::vector<std::pair<uint256, txiter> > vTxHashes; //!< All tx hashes/entries in mapTx, in random order
+ std::vector<std::pair<uint256, txiter> > vTxHashes; //!< All tx witness hashes/entries in mapTx, in random order
struct CompareIteratorByHash {
bool operator()(const txiter &a, const txiter &b) const {
@@ -491,15 +478,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.
- * minReasonableRelayFee should be a feerate which is, roughly, somewhere
- * around what it "costs" to relay a transaction around the network and
- * below which we would reasonably say a transaction has 0-effective-fee.
*/
- CTxMemPool(const CFeeRate& _minReasonableRelayFee);
- ~CTxMemPool();
+ CTxMemPool(CBlockPolicyEstimator* estimator = nullptr);
/**
* If sanity-checking is turned on, check makes sure the pool is
@@ -514,14 +497,14 @@ public:
// to track size/count of descendant transactions. First version of
// addUnchecked can be used to have it call CalculateMemPoolAncestors(), and
// then invoke the second version.
- bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true);
- bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate = true);
+ 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, std::list<CTransaction>& removed);
+ void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
- void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);
- void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
- std::list<CTransaction>& conflicts, bool fCurrentEstimate = true);
+ 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);
@@ -536,8 +519,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:
@@ -548,18 +531,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)
@@ -580,7 +563,7 @@ public:
/** The minimum fee to get into the mempool, which may itself not be enough
* for larger-sized transactions.
- * The minReasonableRelayFee constructor arg is used to bound the time it
+ * The incrementalRelayFee policy variable is used to bound the time it
* takes the fee rate to go back down all the way to 0. When the feerate
* would otherwise be half of this, it is set to 0 instead.
*/
@@ -595,6 +578,9 @@ public:
/** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. */
int Expire(int64_t time);
+ /** Returns false if the transaction is in the mempool and not within the chain limit specified. */
+ bool TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const;
+
unsigned long size()
{
LOCK(cs);
@@ -613,34 +599,15 @@ public:
return (mapTx.count(hash) != 0);
}
- std::shared_ptr<const CTransaction> get(const uint256& hash) const;
+ CTransactionRef get(const uint256& hash) const;
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
@@ -677,7 +644,7 @@ 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);
};
/**
@@ -695,17 +662,4 @@ public:
bool HaveCoins(const uint256 &txid) const;
};
-// We want to sort transactions by coin age priority
-typedef std::pair<double, CTxMemPool::txiter> TxCoinAgePriority;
-
-struct TxCoinAgePriorityCompare
-{
- bool operator()(const TxCoinAgePriority& a, const TxCoinAgePriority& b)
- {
- if (a.first == b.first)
- return CompareTxMemPoolEntryByScore()(*(b.second), *(a.second)); //Reverse order to make sort less than
- return a.first < b.first;
- }
-};
-
#endif // BITCOIN_TXMEMPOOL_H
diff --git a/src/ui_interface.cpp b/src/ui_interface.cpp
index c778e40a90..74a13e0e05 100644
--- a/src/ui_interface.cpp
+++ b/src/ui_interface.cpp
@@ -18,6 +18,11 @@ void InitWarning(const std::string& str)
uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING);
}
+std::string AmountHighWarn(const std::string& optname)
+{
+ return strprintf(_("%s is set very high!"), optname);
+}
+
std::string AmountErrMsg(const char* const optname, const std::string& strValue)
{
return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue);
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 7e6557f8e2..065d23fbb4 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -85,6 +85,9 @@ public:
/** Number of network connections changed. */
boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged;
+ /** Network activity state changed. */
+ boost::signals2::signal<void (bool networkActive)> NotifyNetworkActiveChanged;
+
/**
* Status bar alerts changed.
*/
@@ -112,6 +115,8 @@ void InitWarning(const std::string& str);
/** Show error message **/
bool InitError(const std::string& str);
+std::string AmountHighWarn(const std::string& optname);
+
std::string AmountErrMsg(const char* const optname, const std::string& strValue);
extern CClientUIInterface uiInterface;
diff --git a/src/uint256.cpp b/src/uint256.cpp
index f22ddcd1ef..c4c7b716fe 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -20,10 +20,7 @@ base_blob<BITS>::base_blob(const std::vector<unsigned char>& vch)
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 dd8432d74c..a92ce07f11 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -78,11 +78,6 @@ public:
return sizeof(data);
}
- unsigned int GetSerializeSize(int nType, int nVersion) const
- {
- return sizeof(data);
- }
-
uint64_t GetUint64(int pos) const
{
const uint8_t* ptr = data + pos * 8;
@@ -97,13 +92,13 @@ public:
}
template<typename Stream>
- void Serialize(Stream& s, int nType, int nVersion) const
+ void Serialize(Stream& s) const
{
s.write((char*)data, sizeof(data));
}
template<typename Stream>
- void Unserialize(Stream& s, int nType, int nVersion)
+ void Unserialize(Stream& s)
{
s.read((char*)data, sizeof(data));
}
diff --git a/src/undo.h b/src/undo.h
index d4fc84c90c..a94e31f5cc 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// 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.
@@ -27,29 +27,23 @@ public:
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) { }
- unsigned int GetSerializeSize(int nType, int nVersion) const {
- return ::GetSerializeSize(VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion) +
- (nHeight > 0 ? ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion) : 0) +
- ::GetSerializeSize(CTxOutCompressor(REF(txout)), nType, nVersion);
- }
-
template<typename Stream>
- void Serialize(Stream &s, int nType, int nVersion) const {
- ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion);
+ void Serialize(Stream &s) const {
+ ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)));
if (nHeight > 0)
- ::Serialize(s, VARINT(this->nVersion), nType, nVersion);
- ::Serialize(s, CTxOutCompressor(REF(txout)), nType, nVersion);
+ ::Serialize(s, VARINT(this->nVersion));
+ ::Serialize(s, CTxOutCompressor(REF(txout)));
}
template<typename Stream>
- void Unserialize(Stream &s, int nType, int nVersion) {
+ void Unserialize(Stream &s) {
unsigned int nCode = 0;
- ::Unserialize(s, VARINT(nCode), nType, nVersion);
+ ::Unserialize(s, VARINT(nCode));
nHeight = nCode / 2;
fCoinBase = nCode & 1;
if (nHeight > 0)
- ::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
- ::Unserialize(s, REF(CTxOutCompressor(REF(txout))), nType, nVersion);
+ ::Unserialize(s, VARINT(this->nVersion));
+ ::Unserialize(s, REF(CTxOutCompressor(REF(txout))));
}
};
@@ -63,7 +57,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vprevout);
}
};
@@ -77,7 +71,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vtxundo);
}
};
diff --git a/src/univalue/.travis.yml b/src/univalue/.travis.yml
index d318d9cc8f..132743d349 100644
--- a/src/univalue/.travis.yml
+++ b/src/univalue/.travis.yml
@@ -1,4 +1,3 @@
-
language: cpp
compiler:
@@ -26,6 +25,7 @@ addons:
- pkg-config
before_script:
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall libtool; brew install libtool; fi
- if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi
- test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index 8428b1c683..e8ce283519 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -56,7 +56,7 @@ public:
bool setNumStr(const std::string& val);
bool setInt(uint64_t val);
bool setInt(int64_t val);
- bool setInt(int val) { return setInt((int64_t)val); }
+ bool setInt(int val_) { return setInt((int64_t)val_); }
bool setFloat(double val);
bool setStr(const std::string& val);
bool setArray();
@@ -95,28 +95,28 @@ public:
bool push_backV(const std::vector<UniValue>& vec);
bool pushKV(const std::string& key, const UniValue& val);
- bool pushKV(const std::string& key, const std::string& val) {
- UniValue tmpVal(VSTR, val);
+ bool pushKV(const std::string& key, const std::string& val_) {
+ UniValue tmpVal(VSTR, val_);
return pushKV(key, tmpVal);
}
bool pushKV(const std::string& key, const char *val_) {
- std::string val(val_);
- return pushKV(key, val);
+ std::string _val(val_);
+ return pushKV(key, _val);
}
- bool pushKV(const std::string& key, int64_t val) {
- UniValue tmpVal(val);
+ bool pushKV(const std::string& key, int64_t val_) {
+ UniValue tmpVal(val_);
return pushKV(key, tmpVal);
}
- bool pushKV(const std::string& key, uint64_t val) {
- UniValue tmpVal(val);
+ bool pushKV(const std::string& key, uint64_t val_) {
+ UniValue tmpVal(val_);
return pushKV(key, tmpVal);
}
- bool pushKV(const std::string& key, int val) {
- UniValue tmpVal((int64_t)val);
+ bool pushKV(const std::string& key, int val_) {
+ UniValue tmpVal((int64_t)val_);
return pushKV(key, tmpVal);
}
- bool pushKV(const std::string& key, double val) {
- UniValue tmpVal(val);
+ bool pushKV(const std::string& key, double val_) {
+ UniValue tmpVal(val_);
return pushKV(key, tmpVal);
}
bool pushKVs(const UniValue& obj);
@@ -142,10 +142,10 @@ private:
public:
// Strict type-specific getters, these throw std::runtime_error if the
// value is of unexpected type
- std::vector<std::string> getKeys() const;
- std::vector<UniValue> getValues() const;
+ const std::vector<std::string>& getKeys() const;
+ const std::vector<UniValue>& getValues() const;
bool get_bool() const;
- std::string get_str() const;
+ const std::string& get_str() const;
int get_int() const;
int64_t get_int64() const;
double get_real() const;
diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp
index 0076d6678e..5a2860c13f 100644
--- a/src/univalue/lib/univalue.cpp
+++ b/src/univalue/lib/univalue.cpp
@@ -119,32 +119,29 @@ bool UniValue::setNumStr(const string& val_)
return true;
}
-bool UniValue::setInt(uint64_t val)
+bool UniValue::setInt(uint64_t val_)
{
- string s;
ostringstream oss;
- oss << val;
+ oss << val_;
return setNumStr(oss.str());
}
-bool UniValue::setInt(int64_t val)
+bool UniValue::setInt(int64_t val_)
{
- string s;
ostringstream oss;
- oss << val;
+ oss << val_;
return setNumStr(oss.str());
}
-bool UniValue::setFloat(double val)
+bool UniValue::setFloat(double val_)
{
- string s;
ostringstream oss;
- oss << std::setprecision(16) << val;
+ oss << std::setprecision(16) << val_;
bool ret = setNumStr(oss.str());
typ = VNUM;
@@ -173,12 +170,12 @@ bool UniValue::setObject()
return true;
}
-bool UniValue::push_back(const UniValue& val)
+bool UniValue::push_back(const UniValue& val_)
{
if (typ != VARR)
return false;
- values.push_back(val);
+ values.push_back(val_);
return true;
}
@@ -192,13 +189,13 @@ bool UniValue::push_backV(const std::vector<UniValue>& vec)
return true;
}
-bool UniValue::pushKV(const std::string& key, const UniValue& val)
+bool UniValue::pushKV(const std::string& key, const UniValue& val_)
{
if (typ != VOBJ)
return false;
keys.push_back(key);
- values.push_back(val);
+ values.push_back(val_);
return true;
}
@@ -228,7 +225,7 @@ int UniValue::findKey(const std::string& key) const
bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t)
{
for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
- it != t.end(); it++) {
+ it != t.end(); ++it) {
int idx = findKey(it->first);
if (idx < 0)
return false;
@@ -286,14 +283,14 @@ const UniValue& find_value(const UniValue& obj, const std::string& name)
return NullUniValue;
}
-std::vector<std::string> UniValue::getKeys() const
+const std::vector<std::string>& UniValue::getKeys() const
{
if (typ != VOBJ)
throw std::runtime_error("JSON value is not an object as expected");
return keys;
}
-std::vector<UniValue> UniValue::getValues() const
+const std::vector<UniValue>& UniValue::getValues() const
{
if (typ != VOBJ && typ != VARR)
throw std::runtime_error("JSON value is not an object or array as expected");
@@ -307,7 +304,7 @@ bool UniValue::get_bool() const
return getBool();
}
-std::string UniValue::get_str() const
+const std::string& UniValue::get_str() const
{
if (typ != VSTR)
throw std::runtime_error("JSON value is not a string as expected");
diff --git a/src/util.cpp b/src/util.cpp
index 9a9209c621..653a4f072a 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -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,11 +72,13 @@
#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>
@@ -85,58 +87,42 @@
#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;
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
-map<string, string> mapArgs;
-map<string, vector<string> > mapMultiArgs;
-bool fDebug = false;
+ArgsManager gArgs;
bool fPrintToConsole = false;
bool fPrintToDebugLog = true;
-bool fDaemon = false;
-bool fServer = false;
-string strMiscWarning;
+
bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
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.
@@ -160,9 +146,8 @@ public:
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);
+ // Clear the set of locks now to maintain symmetry with the constructor.
+ ppmutexOpenSSL.reset();
}
}
instance_of_cinit;
@@ -191,7 +176,7 @@ static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
*/
static FILE* fileout = NULL;
static boost::mutex* mutexDebugLog = NULL;
-static list<string> *vMsgsBeforeOpenLog;
+static std::list<std::string>* vMsgsBeforeOpenLog;
static int FileWriteStr(const std::string &str, FILE *fp)
{
@@ -202,7 +187,7 @@ static void DebugPrintInit()
{
assert(mutexDebugLog == NULL);
mutexDebugLog = new boost::mutex();
- vMsgsBeforeOpenLog = new list<string>;
+ vMsgsBeforeOpenLog = new std::list<std::string>;
}
void OpenDebugLog()
@@ -212,47 +197,100 @@ void OpenDebugLog()
assert(fileout == NULL);
assert(vMsgsBeforeOpenLog);
- boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
- fileout = fopen(pathDebug.string().c_str(), "a");
- if (fileout) setbuf(fileout, NULL); // unbuffered
-
- // 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, NULL); // unbuffered
+ // dump buffered messages from before we opened the log
+ while (!vMsgsBeforeOpenLog->empty()) {
+ FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
+ vMsgsBeforeOpenLog->pop_front();
+ }
}
delete vMsgsBeforeOpenLog;
vMsgsBeforeOpenLog = NULL;
}
-bool LogAcceptCategory(const char* category)
+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;
+}
+
+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)
- {
- const vector<string>& categories = mapMultiArgs["-debug"];
- ptrCategory.reset(new set<string>(categories.begin(), categories.end()));
- // thread_specific_ptr automatically deletes the set when the thread ends.
+ 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;
}
/**
@@ -260,18 +298,22 @@ bool LogAcceptCategory(const char* category)
* suppress printing of the timestamp when multiple calls are made that don't
* end in a newline. Initialize it to true, and hold it, in the calling context.
*/
-static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine)
+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;
@@ -287,9 +329,9 @@ static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine
int LogPrintStr(const std::string &str)
{
int ret = 0; // Returns total number of characters written
- static bool fStartedNewLine = true;
+ static std::atomic_bool fStartedNewLine(true);
- string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
+ std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
if (fPrintToConsole)
{
@@ -313,8 +355,8 @@ 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)
+ fs::path pathDebug = GetDataDir() / "debug.log";
+ if (fsbridge::freopen(pathDebug,"a",fileout) != NULL)
setbuf(fileout, NULL); // unbuffered
}
@@ -342,8 +384,9 @@ 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();
@@ -377,36 +420,52 @@ void ParseParameters(int argc, const char* const argv[])
}
}
-std::string GetArg(const std::string& strArg, const std::string& strDefault)
+std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg)
{
+ LOCK(cs_args);
+ return mapMultiArgs.at(strArg);
+}
+
+bool ArgsManager::IsArgSet(const std::string& strArg)
+{
+ LOCK(cs_args);
+ return mapArgs.count(strArg);
+}
+
+std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault)
+{
+ LOCK(cs_args);
if (mapArgs.count(strArg))
return mapArgs[strArg];
return strDefault;
}
-int64_t GetArg(const std::string& strArg, int64_t nDefault)
+int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault)
{
+ LOCK(cs_args);
if (mapArgs.count(strArg))
return atoi64(mapArgs[strArg]);
return nDefault;
}
-bool GetBoolArg(const std::string& strArg, bool fDefault)
+bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault)
{
+ LOCK(cs_args);
if (mapArgs.count(strArg))
return InterpretBool(mapArgs[strArg]);
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;
+ 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"));
@@ -414,6 +473,15 @@ bool SoftSetBoolArg(const std::string& strArg, bool fValue)
return SoftSetArg(strArg, std::string("0"));
}
+void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
+{
+ LOCK(cs_args);
+ mapArgs[strArg] = strValue;
+ mapMultiArgs[strArg].push_back(strValue);
+}
+
+
+
static const int screenWidth = 79;
static const int optIndent = 2;
static const int msgIndent = 7;
@@ -452,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
@@ -479,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);
@@ -496,8 +562,8 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific)
if (!path.empty())
return path;
- if (mapArgs.count("-datadir")) {
- path = fs::system_complete(mapArgs["-datadir"]);
+ if (IsArgSet("-datadir")) {
+ path = fs::system_complete(GetArg("-datadir", ""));
if (!fs::is_directory(path)) {
path = "";
return path;
@@ -515,54 +581,58 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific)
void ClearDatadirCache()
{
- pathCached = boost::filesystem::path();
- pathCachedNetSpecific = boost::filesystem::path();
+ LOCK(csPathCached);
+
+ pathCached = fs::path();
+ pathCachedNetSpecific = fs::path();
}
-boost::filesystem::path GetConfigFile()
+fs::path GetConfigFile(const std::string& confPath)
{
- boost::filesystem::path pathConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME));
+ fs::path pathConfigFile(confPath);
if (!pathConfigFile.is_complete())
pathConfigFile = GetDataDir(false) / pathConfigFile;
return pathConfigFile;
}
-void ReadConfigFile(map<string, string>& mapSettingsRet,
- map<string, vector<string> >& mapMultiSettingsRet)
+void ArgsManager::ReadConfigFile(const std::string& confPath)
{
- boost::filesystem::ifstream streamConfig(GetConfigFile());
+ fs::ifstream streamConfig(GetConfigFile(confPath));
if (!streamConfig.good())
return; // No bitcoin.conf file is OK
- set<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];
- InterpretNegativeSetting(strKey, strValue);
- if (mapSettingsRet.count(strKey) == 0)
- mapSettingsRet[strKey] = strValue;
- mapMultiSettingsRet[strKey].push_back(strValue);
+ LOCK(cs_args);
+ 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
+ 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);
+ }
}
// If datadir is changed in .conf file:
ClearDatadirCache();
}
#ifndef WIN32
-boost::filesystem::path GetPidFile()
+fs::path GetPidFile()
{
- boost::filesystem::path pathPidFile(GetArg("-pid", BITCOIN_PID_FILENAME));
+ fs::path pathPidFile(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);
@@ -571,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(),
@@ -587,13 +657,13 @@ bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest)
* 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 TryCreateDirectory(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_directory(p);
+ } catch (const fs::filesystem_error&) {
+ if (!fs::exists(p) || !fs::is_directory(p))
throw;
}
@@ -601,19 +671,19 @@ bool TryCreateDirectory(const boost::filesystem::path& p)
return false;
}
-void FileCommit(FILE *fileout)
+void FileCommit(FILE *file)
{
- fflush(fileout); // harmless if redundantly called
+ fflush(file); // harmless if redundantly called
#ifdef WIN32
- HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fileout));
+ HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
FlushFileBuffers(hFile);
#else
#if defined(__linux__) || defined(__NetBSD__)
- fdatasync(fileno(fileout));
+ fdatasync(fileno(file));
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
- fcntl(fileno(fileout), F_FULLFSYNC, 0);
+ fcntl(fileno(file), F_FULLFSYNC, 0);
#else
- fsync(fileno(fileout));
+ fsync(fileno(file));
#endif
#endif
}
@@ -697,21 +767,25 @@ 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(begin_ptr(vch), 1, vch.size(), file);
+ 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(begin_ptr(vch), 1, nBytes, file);
+ fwrite(vch.data(), 1, nBytes, file);
fclose(file);
}
}
@@ -720,10 +794,8 @@ void ShrinkDebugFile()
}
#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))
@@ -761,6 +833,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__)
@@ -773,9 +855,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()
@@ -801,11 +883,10 @@ int GetNumCores()
std::string CopyrightHolders(const std::string& strPrefix)
{
- std::string strCopyrightHolders = strPrefix + _(COPYRIGHT_HOLDERS);
- if (strCopyrightHolders.find("%s") != strCopyrightHolders.npos) {
- strCopyrightHolders = strprintf(strCopyrightHolders, _(COPYRIGHT_HOLDERS_SUBSTITUTION));
- }
- if (strCopyrightHolders.find("Bitcoin Core developers") == strCopyrightHolders.npos) {
+ std::string strCopyrightHolders = strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION));
+
+ // Check for untranslated substitution to make sure Bitcoin Core copyright is not removed by accident
+ if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Bitcoin Core") == std::string::npos) {
strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers";
}
return strCopyrightHolders;
diff --git a/src/util.h b/src/util.h
index ac4b947785..229478d835 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -15,6 +15,8 @@
#endif
#include "compat.h"
+#include "fs.h"
+#include "sync.h"
#include "tinyformat.h"
#include "utiltime.h"
@@ -25,7 +27,6 @@
#include <string>
#include <vector>
-#include <boost/filesystem/path.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/thread/exceptions.hpp>
@@ -41,13 +42,9 @@ public:
boost::signals2::signal<std::string (const char* psz)> Translate;
};
-extern std::map<std::string, std::string> mapArgs;
-extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
-extern bool fDebug;
extern bool fPrintToConsole;
extern bool fPrintToDebugLog;
-extern bool fServer;
-extern std::string strMiscWarning;
+
extern bool fLogTimestamps;
extern bool fLogTimeMicros;
extern bool fLogIPs;
@@ -57,6 +54,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.
@@ -70,62 +69,101 @@ 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 LogPrintf(...) LogPrint(NULL, __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; }
-template<typename T1, typename... Args>
-static inline int LogPrint(const char* category, const char* fmt, const T1& v1, const Args&... args)
-{
- if(!LogAcceptCategory(category)) return 0; \
- return LogPrintStr(tfm::format(fmt, v1, args...));
-}
+#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)
-template<typename T1, typename... Args>
-bool error(const char* fmt, const T1& v1, const Args&... args)
-{
- LogPrintStr("ERROR: " + tfm::format(fmt, v1, args...) + "\n");
- return false;
-}
+#define LogPrint(category, ...) do { \
+ if (LogAcceptCategory((category))) { \
+ LogPrintf(__VA_ARGS__); \
+ } \
+} while(0)
-/**
- * Zero-arg versions of logging and error, these are not covered by
- * the variadic templates above (and don't take format arguments but
- * bare strings).
- */
-static inline int LogPrint(const char* category, const char* s)
+template<typename... Args>
+bool error(const char* fmt, const Args&... args)
{
- if(!LogAcceptCategory(category)) return 0;
- return LogPrintStr(s);
-}
-static inline bool error(const char* s)
-{
- LogPrintStr(std::string("ERROR: ") + s + "\n");
+ LogPrintStr("ERROR: " + tfm::format(fmt, args...) + "\n");
return false;
}
void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
-void ParseParameters(int argc, const char*const argv[]);
-void FileCommit(FILE *fileout);
+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 TryCreateDirectory(const fs::path& p);
+fs::path GetDefaultDataDir();
+const fs::path &GetDataDir(bool fNetSpecific = true);
void ClearDatadirCache();
-boost::filesystem::path GetConfigFile();
+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(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
#ifdef WIN32
-boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
+fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
void OpenDebugLog();
void ShrinkDebugFile();
@@ -140,6 +178,24 @@ inline bool IsSwitchChar(char c)
#endif
}
+class ArgsManager
+{
+protected:
+ 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);
+ std::vector<std::string> GetArgs(const std::string& strArg);
+/**
+ * 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
*
@@ -185,6 +241,58 @@ bool SoftSetArg(const std::string& strArg, const std::string& strValue);
*/
bool SoftSetBoolArg(const std::string& strArg, bool fValue);
+// Forces a arg setting, used only in testing
+void ForceSetArg(const std::string& strArg, const std::string& strValue);
+};
+
+extern ArgsManager gArgs;
+
+// wrappers using the global ArgsManager:
+static inline void ParseParameters(int argc, const char*const argv[])
+{
+ gArgs.ParseParameters(argc, argv);
+}
+
+static inline void ReadConfigFile(const std::string& confPath)
+{
+ gArgs.ReadConfigFile(confPath);
+}
+
+static inline bool SoftSetArg(const std::string& strArg, const std::string& strValue)
+{
+ return gArgs.SoftSetArg(strArg, strValue);
+}
+
+static inline void ForceSetArg(const std::string& strArg, const std::string& strValue)
+{
+ gArgs.ForceSetArg(strArg, strValue);
+}
+
+static inline bool IsArgSet(const std::string& strArg)
+{
+ return gArgs.IsArgSet(strArg);
+}
+
+static inline std::string GetArg(const std::string& strArg, const std::string& strDefault)
+{
+ return gArgs.GetArg(strArg, strDefault);
+}
+
+static inline int64_t GetArg(const std::string& strArg, int64_t nDefault)
+{
+ return gArgs.GetArg(strArg, nDefault);
+}
+
+static inline bool GetBoolArg(const std::string& strArg, bool fDefault)
+{
+ return gArgs.GetBoolArg(strArg, fDefault);
+}
+
+static inline bool SoftSetBoolArg(const std::string& strArg, bool fValue)
+{
+ return gArgs.SoftSetBoolArg(strArg, fValue);
+}
+
/**
* Format a string to be used as group of options in help messages
*
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/utilstrencodings.cpp b/src/utilstrencodings.cpp
index 5ffdb3be15..74bf66fbf6 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -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,10 @@ bool IsHex(const string& str)
return (str.size() > 0) && (str.size()%2 == 0);
}
-vector<unsigned char> ParseHex(const char* psz)
+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 +86,16 @@ 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)
+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 +137,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 +164,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 +225,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 (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], 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 +290,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 +317,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 +412,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 (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size());
}
static bool ParsePrechecks(const std::string& str)
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index 5744f78c6e..e2a1b9bef9 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -26,7 +26,8 @@
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
};
/**
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
index da590f8889..e07069125d 100644
--- a/src/utiltime.cpp
+++ b/src/utiltime.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -9,16 +9,17 @@
#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);
assert(now > 0);
@@ -27,7 +28,12 @@ int64_t GetTime()
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
*/
@@ -74,8 +77,9 @@ void MilliSleep(int64_t n)
std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime)
{
+ static std::locale classic(std::locale::classic());
// std::locale takes ownership of the pointer
- std::locale loc(std::locale::classic(), new boost::posix_time::time_facet(pszFormat));
+ std::locale loc(classic, new boost::posix_time::time_facet(pszFormat));
std::stringstream ss;
ss.imbue(loc);
ss << boost::posix_time::from_time_t(nTime);
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/main.cpp b/src/validation.cpp
index 73fbe53afb..75a35756d4 100644
--- a/src/main.cpp
+++ b/src/validation.cpp
@@ -1,23 +1,21 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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 "main.h"
+#include "validation.h"
-#include "addrman.h"
#include "arith_uint256.h"
-#include "blockencodings.h"
+#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
#include "consensus/consensus.h"
#include "consensus/merkle.h"
#include "consensus/validation.h"
+#include "fs.h"
#include "hash.h"
#include "init.h"
-#include "merkleblock.h"
-#include "net.h"
#include "policy/fees.h"
#include "policy/policy.h"
#include "pow.h"
@@ -27,6 +25,7 @@
#include "script/script.h"
#include "script/sigcache.h"
#include "script/standard.h"
+#include "timedata.h"
#include "tinyformat.h"
#include "txdb.h"
#include "txmempool.h"
@@ -37,19 +36,16 @@
#include "utilstrencodings.h"
#include "validationinterface.h"
#include "versionbits.h"
+#include "warnings.h"
#include <atomic>
#include <sstream>
#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
@@ -63,18 +59,16 @@ CCriticalSection cs_main;
BlockMap mapBlockIndex;
CChain chainActive;
CBlockIndex *pindexBestHeader = NULL;
-int64_t nTimeBestReceived = 0;
CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange;
int nScriptCheckThreads = 0;
-bool fImporting = false;
+std::atomic_bool fImporting(false);
bool fReindex = false;
bool fTxIndex = false;
bool fHavePruned = false;
bool fPruneMode = false;
bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
bool fRequireStandard = true;
-unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300;
@@ -82,42 +76,20 @@ uint64_t nPruneTarget = 0;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
+uint256 hashAssumeValid;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
-CTxMemPool mempool(::minRelayTxFee);
-FeeFilterRounder filterRounder(::minRelayTxFee);
+CBlockPolicyEstimator feeEstimator;
+CTxMemPool mempool(&feeEstimator);
-struct IteratorComparator
-{
- template<typename I>
- bool operator()(const I& a, const I& b)
- {
- return &(*a) < &(*b);
- }
-};
-
-struct COrphanTx {
- CTransaction tx;
- 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);
-void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
-/**
- * Returns true if there are nRequired or more blocks of minVersion or above
- * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards.
- */
-static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams);
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 {
@@ -150,13 +122,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;
- /** Number of nodes with fSyncStarted. */
- int nSyncStarted = 0;
+ 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;
@@ -173,488 +143,19 @@ namespace {
*/
CCriticalSection cs_nBlockSequenceId;
/** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
- uint32_t nBlockSequenceId = 1;
-
- /**
- * Sources of received blocks, saved to be able to send them reject
- * messages or ban them when processing happens afterwards. Protected by
- * cs_main.
- */
- map<uint256, NodeId> mapBlockSource;
-
- /**
- * Filter for transactions that were recently rejected by
- * AcceptToMemoryPool. These are not rerequested until the chain tip
- * changes, at which point the entire filter is reset. Protected by
- * cs_main.
- *
- * Without this filter we'd be re-requesting txs from each of our peers,
- * increasing bandwidth consumption considerably. For instance, with 100
- * peers, half of which relay a tx we don't accept, that might be a 50x
- * bandwidth increase. A flooding attacker attempting to roll-over the
- * filter using minimum-sized, 60byte, transactions might manage to send
- * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a
- * two minute window to send invs to us.
- *
- * Decreasing the false positive rate is fairly cheap, so we pick one in a
- * million to make it highly unlikely for users to have issues with this
- * filter.
- *
- * Memory used: 1.3 MB
- */
- boost::scoped_ptr<CRollingBloomFilter> recentRejects;
- uint256 hashRecentRejectsChainTip;
-
- /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
- struct QueuedBlock {
- uint256 hash;
- CBlockIndex* pindex; //!< Optional.
- 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;
-
- /** Stack of nodes which we have set to announce using compact blocks */
- list<NodeId> lNodesAnnouncingHeaderAndIDs;
-
- /** Number of preferable block download peers. */
- int nPreferredDownload = 0;
+ int32_t nBlockSequenceId = 1;
+ /** Decreasing counter (used by subsequent preciousblock calls). */
+ int32_t nBlockReverseSequenceId = -1;
+ /** chainwork for the last block that preciousblock has been applied to. */
+ arith_uint256 nLastPreciousChainwork = 0;
/** Dirty block index entries. */
- set<CBlockIndex*> setDirtyBlockIndex;
+ std::set<CBlockIndex*> setDirtyBlockIndex;
/** Dirty block file entries. */
- set<int> setDirtyFileInfo;
-
- /** Number of peers from which we're downloading blocks. */
- int nPeersWithValidatedDownloads = 0;
-
- /** Relay map, protected by cs_main. */
- typedef std::map<uint256, std::shared_ptr<const CTransaction>> MapRelay;
- 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 {
-
-struct CBlockReject {
- unsigned char chRejectCode;
- string strRejectReason;
- uint256 hashBlock;
-};
-
-/**
- * Maintain validation-specific state about nodes, protected by cs_main, instead
- * by CNode's own locks. This simplifies asynchronous operation, where
- * processing of incoming data is done after the ProcessMessage call returns,
- * and we're no longer holding the node's locks.
- */
-struct CNodeState {
- //! The peer's address
- CService address;
- //! Whether we have a fully established connection.
- bool fCurrentlyConnected;
- //! Accumulated misbehaviour score for this peer.
- int nMisbehavior;
- //! Whether this peer should be disconnected and banned (unless whitelisted).
- bool fShouldBan;
- //! String name of this peer (debugging/logging purposes).
- std::string name;
- //! List of asynchronously-determined block rejections to notify this peer about.
- std::vector<CBlockReject> rejects;
- //! The best known block we know this peer has announced.
- CBlockIndex *pindexBestKnownBlock;
- //! The hash of the last unknown block this peer has announced.
- uint256 hashLastUnknownBlock;
- //! The last full block we both have.
- CBlockIndex *pindexLastCommonBlock;
- //! The best header we have sent our peer.
- CBlockIndex *pindexBestHeaderSent;
- //! Length of current-streak of unconnecting headers announcements
- int nUnconnectingHeaders;
- //! Whether we've started headers synchronization with this peer.
- bool fSyncStarted;
- //! Since when we're stalling block download progress (in microseconds), or 0.
- int64_t nStallingSince;
- list<QueuedBlock> vBlocksInFlight;
- //! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
- int64_t nDownloadingSince;
- int nBlocksInFlight;
- int nBlocksInFlightValidHeaders;
- //! Whether we consider this a preferred download peer.
- bool fPreferredDownload;
- //! Whether this peer wants invs or headers (when possible) for block announcements.
- bool fPreferHeaders;
- //! Whether this peer wants invs or cmpctblocks (when possible) for block announcements.
- bool fPreferHeaderAndIDs;
- //! Whether this peer will send us cmpctblocks if we request them
- bool fProvidesHeaderAndIDs;
- //! Whether this peer can give us witnesses
- bool fHaveWitness;
-
- CNodeState() {
- fCurrentlyConnected = false;
- nMisbehavior = 0;
- fShouldBan = false;
- pindexBestKnownBlock = NULL;
- hashLastUnknownBlock.SetNull();
- pindexLastCommonBlock = NULL;
- pindexBestHeaderSent = NULL;
- nUnconnectingHeaders = 0;
- fSyncStarted = false;
- nStallingSince = 0;
- nDownloadingSince = 0;
- nBlocksInFlight = 0;
- nBlocksInFlightValidHeaders = 0;
- fPreferredDownload = false;
- fPreferHeaders = false;
- fPreferHeaderAndIDs = false;
- fProvidesHeaderAndIDs = false;
- fHaveWitness = false;
- }
-};
-
-/** Map maintaining per-node state. Requires cs_main. */
-map<NodeId, CNodeState> mapNodeState;
-
-// Requires cs_main.
-CNodeState *State(NodeId pnode) {
- map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);
- if (it == mapNodeState.end())
- return NULL;
- return &it->second;
-}
-
-int GetHeight()
-{
- LOCK(cs_main);
- return chainActive.Height();
-}
-
-void UpdatePreferredDownload(CNode* node, CNodeState* state)
-{
- nPreferredDownload -= state->fPreferredDownload;
-
- // Whether this node should be marked as a preferred download node.
- state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient;
-
- nPreferredDownload += state->fPreferredDownload;
-}
-
-void InitializeNode(NodeId nodeid, const CNode *pnode) {
- LOCK(cs_main);
- CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
- state.name = pnode->addrName;
- state.address = pnode->addr;
-}
-
-void FinalizeNode(NodeId nodeid) {
- LOCK(cs_main);
- CNodeState *state = State(nodeid);
-
- if (state->fSyncStarted)
- nSyncStarted--;
-
- if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
- AddressCurrentlyConnected(state->address);
- }
-
- 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);
- }
-}
-
-// Requires cs_main.
-// 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);
- if (itInFlight != mapBlocksInFlight.end()) {
- CNodeState *state = State(itInFlight->second.first);
- state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;
- if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) {
- // Last validated block on the queue was received.
- nPeersWithValidatedDownloads--;
- }
- if (state->vBlocksInFlight.begin() == itInFlight->second.second) {
- // First block on the queue was received, update the start download time for the next one
- state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros());
- }
- state->vBlocksInFlight.erase(itInFlight->second.second);
- state->nBlocksInFlight--;
- state->nStallingSince = 0;
- mapBlocksInFlight.erase(itInFlight);
- return true;
- }
- return false;
-}
-
-// 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, CBlockIndex *pindex = NULL, list<QueuedBlock>::iterator **pit = NULL) {
- CNodeState *state = State(nodeid);
- assert(state != NULL);
-
- // Short-circuit most stuff in case its from the same node
- map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
- if (itInFlight != mapBlocksInFlight.end() && itInFlight->second.first == nodeid) {
- *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)});
- 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) {
- nPeersWithValidatedDownloads++;
- }
- itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it))).first;
- if (pit)
- *pit = &itInFlight->second.second;
- return true;
-}
-
-/** Check whether the last unknown block a peer advertised is not yet known. */
-void ProcessBlockAvailability(NodeId nodeid) {
- CNodeState *state = State(nodeid);
- assert(state != NULL);
-
- 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)
- state->pindexBestKnownBlock = itOld->second;
- state->hashLastUnknownBlock.SetNull();
- }
- }
-}
-
-/** 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);
-
- 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)
- state->pindexBestKnownBlock = it->second;
- } else {
- // An unknown block was announced; just assume that the latest one is the best one.
- state->hashLastUnknownBlock = hash;
- }
-}
-
-void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom) {
- if (nLocalServices & NODE_WITNESS) {
- // Don't ever request compact blocks when segwit is enabled.
- return;
- }
- if (nodestate->fProvidesHeaderAndIDs) {
- BOOST_FOREACH(const NodeId nodeid, lNodesAnnouncingHeaderAndIDs)
- if (nodeid == pfrom->GetId())
- return;
- bool fAnnounceUsingCMPCTBLOCK = false;
- uint64_t nCMPCTBLOCKVersion = 1;
- if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
- // As per BIP152, we only get 3 of our peers to announce
- // blocks using compact encodings.
- CNode* pnodeStop = FindNode(lNodesAnnouncingHeaderAndIDs.front());
- if (pnodeStop) {
- pnodeStop->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
- lNodesAnnouncingHeaderAndIDs.pop_front();
- }
- }
- fAnnounceUsingCMPCTBLOCK = true;
- pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
- lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());
- }
-}
-
-// Requires cs_main
-bool CanDirectFetch(const Consensus::Params &consensusParams)
-{
- return chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20;
-}
-
-// Requires cs_main
-bool PeerHasHeader(CNodeState *state, CBlockIndex *pindex)
-{
- if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight))
- return true;
- if (state->pindexBestHeaderSent && pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight))
- return true;
- return false;
-}
-
-/** Find the last common ancestor two blocks have.
- * Both pa and pb must be non-NULL. */
-CBlockIndex* LastCommonAncestor(CBlockIndex* pa, 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<CBlockIndex*>& vBlocks, NodeId& nodeStaller) {
- if (count == 0)
- return;
-
- vBlocks.reserve(vBlocks.size() + count);
- CNodeState *state = State(nodeid);
- assert(state != NULL);
-
- // Make sure pindexBestKnownBlock is up to date, we'll need it.
- ProcessBlockAvailability(nodeid);
-
- if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) {
- // This peer has nothing interesting.
- return;
- }
-
- if (state->pindexLastCommonBlock == NULL) {
- // 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())];
- }
-
- // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor
- // of its current tip anymore. Go back enough to fix that.
- state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock);
- if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
- return;
-
- std::vector<CBlockIndex*> vToFetch;
- CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
- // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
- // linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
- // download that next block if the window were 1 larger.
- int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW;
- int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
- NodeId waitingfor = -1;
- while (pindexWalk->nHeight < nMaxHeight) {
- // Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards
- // pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive
- // as iterating over ~100 CBlockIndex* entries anyway.
- int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max<int>(count - vBlocks.size(), 128));
- vToFetch.resize(nToFetch);
- pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch);
- vToFetch[nToFetch - 1] = pindexWalk;
- for (unsigned int i = nToFetch - 1; i > 0; i--) {
- vToFetch[i - 1] = vToFetch[i]->pprev;
- }
-
- // Iterate over those blocks in vToFetch (in forward direction), adding the ones that
- // are not yet downloaded and not in flight to vBlocks. In the mean time, update
- // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's
- // already part of our chain (and therefore don't need it even if pruned).
- BOOST_FOREACH(CBlockIndex* pindex, vToFetch) {
- if (!pindex->IsValid(BLOCK_VALID_TREE)) {
- // We consider the chain that this peer is on invalid.
- return;
- }
- if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
- if (pindex->nChainTx)
- state->pindexLastCommonBlock = pindex;
- } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
- // The block is not already downloaded, and not yet in flight.
- if (pindex->nHeight > nWindowEnd) {
- // We reached the end of the window.
- if (vBlocks.size() == 0 && waitingfor != nodeid) {
- // We aren't able to fetch anything, but we would be if the download window was one larger.
- nodeStaller = waitingfor;
- }
- return;
- }
- vBlocks.push_back(pindex);
- if (vBlocks.size() == count) {
- return;
- }
- } else if (waitingfor == -1) {
- // This is the first already-in-flight block.
- waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first;
- }
- }
- }
-}
-
+ std::set<int> setDirtyFileInfo;
} // anon namespace
-bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
- LOCK(cs_main);
- CNodeState *state = State(nodeid);
- if (state == NULL)
- 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) {
- if (queue.pindex)
- stats.vHeightInFlight.push_back(queue.pindex->nHeight);
- }
- return true;
-}
-
-void RegisterNodeSignals(CNodeSignals& nodeSignals)
-{
- nodeSignals.GetHeight.connect(&GetHeight);
- nodeSignals.ProcessMessages.connect(&ProcessMessages);
- nodeSignals.SendMessages.connect(&SendMessages);
- nodeSignals.InitializeNode.connect(&InitializeNode);
- nodeSignals.FinalizeNode.connect(&FinalizeNode);
-}
-
-void UnregisterNodeSignals(CNodeSignals& nodeSignals)
-{
- nodeSignals.GetHeight.disconnect(&GetHeight);
- nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
- nodeSignals.SendMessages.disconnect(&SendMessages);
- nodeSignals.InitializeNode.disconnect(&InitializeNode);
- nodeSignals.FinalizeNode.disconnect(&FinalizeNode);
-}
-
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
{
// Find the first block the caller has in the main chain
@@ -676,111 +177,16 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
CCoinsViewCache *pcoinsTip = NULL;
CBlockTreeDB *pblocktree = NULL;
-//////////////////////////////////////////////////////////////////////////////
-//
-// mapOrphanTransactions
-//
-
-bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
-{
- uint256 hash = tx.GetHash();
- if (mapOrphanTransactions.count(hash))
- return false;
-
- // Ignore big transactions, to avoid a
- // send-big-orphans memory exhaustion attack. If a peer has a legitimate
- // large transaction with a missing parent then we assume
- // it will rebroadcast it later, after the parent transaction(s)
- // have been mined or received.
- // 100 orphans, each of which is at most 99,999 bytes big is
- // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):
- unsigned int sz = GetTransactionCost(tx);
- if (sz >= MAX_STANDARD_TX_COST)
- {
- LogPrint("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) {
- mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first);
- }
-
- LogPrint("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);
- if (it == mapOrphanTransactions.end())
- return 0;
- BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin)
- {
- auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout);
- if (itPrev == mapOrphanTransactionsByPrev.end())
- continue;
- itPrev->second.erase(it);
- if (itPrev->second.empty())
- mapOrphanTransactionsByPrev.erase(itPrev);
- }
- mapOrphanTransactions.erase(it);
- return 1;
-}
-
-void EraseOrphansFor(NodeId peer)
-{
- int nErased = 0;
- map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
- while (iter != mapOrphanTransactions.end())
- {
- 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);
-}
-
+enum FlushStateMode {
+ FLUSH_STATE_NONE,
+ FLUSH_STATE_IF_NEEDED,
+ FLUSH_STATE_PERIODIC,
+ FLUSH_STATE_ALWAYS
+};
-unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
-{
- unsigned int nEvicted = 0;
- static int64_t nNextSweep;
- int64_t nNow = GetTime();
- if (nNextSweep <= nNow) {
- // 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();
- while (iter != mapOrphanTransactions.end())
- {
- map<uint256, COrphanTx>::iterator maybeErase = iter++;
- if (maybeErase->second.nTimeExpire <= nNow) {
- nErased += EraseOrphanTx(maybeErase->second.tx.GetHash());
- } else {
- nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime);
- }
- }
- // 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);
- }
- while (mapOrphanTransactions.size() > nMaxOrphans)
- {
- // Evict a random orphan:
- uint256 randomhash = GetRandHash();
- map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
- if (it == mapOrphanTransactions.end())
- it = mapOrphanTransactions.begin();
- EraseOrphanTx(it->first);
- ++nEvicted;
- }
- return nEvicted;
-}
+// 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)
{
@@ -788,7 +194,7 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
return true;
if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
return true;
- BOOST_FOREACH(const CTxIn& txin, tx.vin) {
+ for (const auto& txin : tx.vin) {
if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL))
return false;
}
@@ -1002,11 +408,11 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
unsigned int GetLegacySigOpCount(const CTransaction& tx)
{
unsigned int nSigOps = 0;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ for (const auto& txin : tx.vin)
{
nSigOps += txin.scriptSig.GetSigOpCount(false);
}
- BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ for (const auto& txout : tx.vout)
{
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
}
@@ -1042,7 +448,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
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, i < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[i].scriptWitness : NULL, flags);
+ nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, &tx.vin[i].scriptWitness, flags);
}
return nSigOps;
}
@@ -1051,7 +457,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
-bool CheckTransaction(const CTransaction& tx, CValidationState &state)
+bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)
{
// Basic checks that don't depend on any context
if (tx.vin.empty())
@@ -1064,7 +470,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
// Check for negative or overflow output values
CAmount nValueOut = 0;
- BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ for (const auto& txout : tx.vout)
{
if (txout.nValue < 0)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
@@ -1075,13 +481,14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
}
- // Check for duplicate inputs
- set<COutPoint> vInOutPoints;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- if (vInOutPoints.count(txin.prevout))
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
- vInOutPoints.insert(txin.prevout);
+ // 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())
@@ -1091,7 +498,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
}
else
{
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ for (const auto& txin : tx.vin)
if (txin.prevout.IsNull())
return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
}
@@ -1101,8 +508,9 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
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;
pool.TrimToSize(limit, &vNoSpendsRemaining);
@@ -1119,10 +527,23 @@ std::string FormatStateMessage(const CValidationState &state)
state.GetRejectCode());
}
-bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
- std::vector<uint256>& vHashTxnToUncache)
+static bool IsCurrentForFeeEstimation()
+{
+ AssertLockHeld(cs_main);
+ if (IsInitialBlockDownload())
+ return false;
+ if (chainActive.Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE))
+ return false;
+ if (chainActive.Height() < pindexBestHeader->nHeight - 1)
+ return false;
+ return true;
+}
+
+bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree,
+ bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
+ bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, std::vector<uint256>& vHashTxnToUncache)
{
+ const CTransaction& tx = *ptx;
const uint256 hash = tx.GetHash();
AssertLockHeld(cs_main);
if (pfMissingInputs)
@@ -1135,22 +556,15 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if (tx.IsCoinBase())
return state.DoS(100, false, REJECT_INVALID, "coinbase");
- // Don't relay version 2 transactions until CSV is active, and we can be
- // sure that such transactions will be mined (unless we're on
- // -testnet/-regtest).
- const CChainParams& chainparams = Params();
- if (fRequireStandard && tx.nVersion >= 2 && VersionBitsTipState(chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV) != THRESHOLD_ACTIVE) {
- return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx");
- }
-
// Reject transactions with witness before segregated witness activates (override with -prematurewitness)
- if (!GetBoolArg("-prematurewitness",false) && !tx.wit.IsNull() && !IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus())) {
+ bool witnessEnabled = IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus());
+ if (!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;
- if (fRequireStandard && !IsStandardTx(tx, reason))
+ std::string reason;
+ if (fRequireStandard && !IsStandardTx(tx, reason, witnessEnabled))
return state.DoS(0, false, REJECT_NONSTANDARD, reason);
// Only accept nLockTime-using transactions that can be mined in the next
@@ -1164,7 +578,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
return state.Invalid(false, REJECT_ALREADY_KNOWN, "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)
@@ -1179,7 +593,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// nSequence >= maxint-1 on all inputs.
//
// maxint-1 is picked to still allow use of nLockTime by
- // non-replacable transactions. All inputs rather than just one
+ // 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.
//
@@ -1190,9 +604,9 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
bool fReplacementOptOut = true;
if (fEnableReplacement)
{
- BOOST_FOREACH(const CTxIn &txin, ptxConflicting->vin)
+ BOOST_FOREACH(const CTxIn &_txin, ptxConflicting->vin)
{
- if (txin.nSequence < std::numeric_limits<unsigned int>::max()-1)
+ if (_txin.nSequence < std::numeric_limits<unsigned int>::max()-1)
{
fReplacementOptOut = false;
break;
@@ -1265,17 +679,17 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if (fRequireStandard && !AreInputsStandard(tx, view))
return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs");
+ // Check for non-standard witness in P2WSH
+ if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, view))
+ return state.DoS(0, false, REJECT_NONSTANDARD, "bad-witness-nonstandard", true);
+
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS);
CAmount nValueOut = tx.GetValueOut();
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.
@@ -1288,7 +702,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
}
}
- CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), 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
@@ -1296,39 +711,18 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
// MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
// merely non-standard transaction.
- if ((nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST) || (nBytesPerSigOp && nSigOpsCost > nSize * WITNESS_SCALE_FACTOR / nBytesPerSigOp))
+ if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST)
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) {
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 (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) {
+ return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "min relay fee not met");
}
if (nAbsurdFee && nFees > nAbsurdFee)
@@ -1375,10 +769,11 @@ 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)
@@ -1479,14 +874,14 @@ 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))));
}
}
@@ -1497,16 +892,18 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true)) {
+ PrecomputedTransactionData txdata(tx);
+ if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, 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 (CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true) &&
- !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true)) {
- // Only the witness is wrong, so the transaction itself may be fine.
+ 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, txdata) &&
+ !CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, 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
@@ -1518,7 +915,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// 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))
+ if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata))
{
return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s",
__func__, hash.ToString(), FormatStateMessage(state));
@@ -1527,16 +924,24 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Remove conflicting transactions from the mempool
BOOST_FOREACH(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 it isn't a
+ // BIP 125 replacement transaction (may not be widely supported), the
+ // node is not behind, and the transaction is not dependent on any other
+ // transactions in the mempool.
+ bool validForFeeEstimation = !fReplacementTransaction && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx);
// Store transaction in memory
- pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());
+ pool.addUnchecked(hash, entry, setAncestors, validForFeeEstimation);
// trim mempool and check if tx was trimmed
if (!fOverrideMempoolLimit) {
@@ -1546,34 +951,45 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
}
}
- SyncWithWallets(tx, NULL, NULL);
+ GetMainSignals().TransactionAddedToMempool(ptx);
return true;
}
-bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
+bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
+ bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
+ bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
{
std::vector<uint256> vHashTxToUncache;
- bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
+ bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
if (!res) {
BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache)
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);
return res;
}
-/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */
-bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow)
+bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
+ bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
+ bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
+{
+ return AcceptToMemoryPoolWithTime(pool, state, tx, fLimitFree, pfMissingInputs, GetTime(), plTxnReplaced, fOverrideMempoolLimit, 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;
LOCK(cs_main);
- std::shared_ptr<const CTransaction> ptx = mempool.get(hash);
+ CTransactionRef ptx = mempool.get(hash);
if (ptx)
{
- txOut = *ptx;
+ txOut = ptx;
return true;
}
@@ -1592,7 +1008,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
hashBlock = header.GetHash();
- if (txOut.GetHash() != hash)
+ if (txOut->GetHash() != hash)
return error("%s: txid mismatch", __func__);
return true;
}
@@ -1613,8 +1029,8 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
if (pindexSlow) {
CBlock block;
if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) {
- BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- if (tx.GetHash() == hash) {
+ for (const auto& tx : block.vtx) {
+ if (tx->GetHash() == hash) {
txOut = tx;
hashBlock = pindexSlow->GetBlockHash();
return true;
@@ -1644,7 +1060,7 @@ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHea
return error("WriteBlockToDisk: OpenBlockFile failed");
// Write index header
- unsigned int nSize = fileout.GetSerializeSize(block);
+ unsigned int nSize = GetSerializeSize(fileout, block);
fileout << FLATDATA(messageStart) << nSize;
// Write block
@@ -1719,17 +1135,16 @@ bool IsInitialBlockDownload()
return false;
if (fImporting || fReindex)
return true;
- if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints()))
+ if (chainActive.Tip() == NULL)
+ return true;
+ if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork))
+ return true;
+ if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
return true;
- bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 ||
- std::max(chainActive.Tip()->GetBlockTime(), pindexBestHeader->GetBlockTime()) < GetTime() - nMaxTipAge);
- if (!state)
- latchToFalse.store(true, std::memory_order_relaxed);
- return state;
+ latchToFalse.store(true, std::memory_order_relaxed);
+ return false;
}
-bool fLargeWorkForkFound = false;
-bool fLargeWorkInvalidChainFound = false;
CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
static void AlertNotify(const std::string& strMessage)
@@ -1753,7 +1168,7 @@ void CheckForkWarningConditions()
{
AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks
- // (we assume we don't get stuck on a fork before the last checkpoint)
+ // (we assume we don't get stuck on a fork before finishing our initial sync)
if (IsInitialBlockDownload())
return;
@@ -1764,7 +1179,7 @@ void CheckForkWarningConditions()
if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6)))
{
- if (!fLargeWorkForkFound && pindexBestForkBase)
+ if (!GetfLargeWorkForkFound() && pindexBestForkBase)
{
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
pindexBestForkBase->phashBlock->ToString() + std::string("'");
@@ -1775,18 +1190,18 @@ void CheckForkWarningConditions()
LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__,
pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(),
pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString());
- fLargeWorkForkFound = true;
+ SetfLargeWorkForkFound(true);
}
else
{
LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__);
- fLargeWorkInvalidChainFound = true;
+ SetfLargeWorkInvalidChainFound(true);
}
}
else
{
- fLargeWorkForkFound = false;
- fLargeWorkInvalidChainFound = false;
+ SetfLargeWorkForkFound(false);
+ SetfLargeWorkInvalidChainFound(false);
}
}
@@ -1823,26 +1238,6 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
CheckForkWarningConditions();
}
-// Requires cs_main.
-void Misbehaving(NodeId pnode, int howmuch)
-{
- if (howmuch == 0)
- return;
-
- CNodeState *state = State(pnode);
- if (state == NULL)
- return;
-
- state->nMisbehavior += howmuch;
- int banscore = GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD);
- if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore)
- {
- LogPrintf("%s: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior);
- state->fShouldBan = true;
- } else
- LogPrintf("%s: %s (%d -> %d)\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior);
-}
-
void static InvalidChainFound(CBlockIndex* pindexNew)
{
if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork)
@@ -1861,17 +1256,6 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
}
void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
- int nDoS = 0;
- if (state.IsInvalid(nDoS)) {
- std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
- if (it != mapBlockSource.end() && State(it->second)) {
- assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
- CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
- State(it->second)->rejects.push_back(reject);
- if (nDoS > 0)
- Misbehaving(it->second, nDoS);
- }
- }
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
@@ -1914,11 +1298,8 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
- const CScriptWitness *witness = (nIn < ptxTo->wit.vtxinwit.size()) ? &ptxTo->wit.vtxinwit[nIn].scriptWitness : NULL;
- if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore), &error)) {
- return false;
- }
- return true;
+ const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
+ return VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error);
}
int GetSpendHeight(const CCoinsViewCache& inputs)
@@ -1974,7 +1355,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
}
}// namespace Consensus
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
@@ -1988,12 +1369,11 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
// Helps prevent CPU exhaustion attacks.
- // Skip ECDSA signature verification when connecting blocks before the
- // last block chain checkpoint. Assuming the checkpoints are valid this
+ // Skip script verification when connecting blocks under the
+ // assumevalid block. Assuming the assumevalid block is valid this
// is safe because block merkle hashes are still computed and checked,
- // and any change will be caught at the next checkpoint. Of course, if
- // the checkpoint is for a chain that's invalid due to false scriptSigs
- // this optimisation would allow an invalid chain to be accepted.
+ // 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) {
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const COutPoint &prevout = tx.vin[i].prevout;
@@ -2001,7 +1381,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
assert(coins);
// Verify signature
- CScriptCheck check(*coins, tx, i, flags, cacheStore);
+ CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -2014,7 +1394,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check2(*coins, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
@@ -2044,7 +1424,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint
return error("%s: OpenUndoFile failed", __func__);
// Write index header
- unsigned int nSize = fileout.GetSerializeSize(blockundo);
+ unsigned int nSize = GetSerializeSize(fileout, blockundo);
fileout << FLATDATA(messageStart) << nSize;
// Write undo data
@@ -2068,7 +1448,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
// Open history file to read
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
- return error("%s: OpenBlockFile failed", __func__);
+ return error("%s: OpenUndoFile failed", __func__);
// Read block
uint256 hashChecksum;
@@ -2093,7 +1473,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
/** Abort with a message */
bool AbortNode(const std::string& strMessage, const std::string& userMessage="")
{
- strMiscWarning = strMessage;
+ SetMiscWarning(strMessage);
LogPrintf("*** %s\n", strMessage);
uiInterface.ThreadSafeMessageBox(
userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage,
@@ -2117,7 +1497,7 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std
* @param out The out point that corresponds to the tx input.
* @return True on success.
*/
-static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out)
+bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out)
{
bool fClean = true;
@@ -2143,28 +1523,40 @@ static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const CO
return fClean;
}
-bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
+enum DisconnectResult
{
- assert(pindex->GetBlockHash() == view.GetBestBlock());
+ DISCONNECT_OK, // All good.
+ DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
+ DISCONNECT_FAILED // Something else went wrong.
+};
- if (pfClean)
- *pfClean = false;
+/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
+ * When UNCLEAN or 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());
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];
+ const CTransaction &tx = *(block.vtx[i]);
uint256 hash = tx.GetHash();
// Check that all outputs are available and match the outputs in the block itself
@@ -2189,8 +1581,10 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
// 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");
+ 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];
@@ -2203,12 +1597,7 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
// 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)
@@ -2296,11 +1685,17 @@ static int64_t nTimeIndex = 0;
static int64_t nTimeCallbacks = 0;
static int64_t nTimeTotal = 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 == NULL) ||
+ (*pindex->phashBlock == block.GetHash()));
int64_t nTimeStart = GetTimeMicros();
// Check it again in case a previous version let a bad block in
@@ -2320,16 +1715,33 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
}
bool fScriptChecks = true;
- if (fCheckpointsEnabled) {
- CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
- if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) {
- // This block is an ancestor of a checkpoint: disable script checks
- fScriptChecks = false;
+ if (!hashAssumeValid.IsNull()) {
+ // We've been configured with the hash of a block which has been externally verified to have a valid history.
+ // A suitable default value is included with the software and updated from time to time. Because validity
+ // relative to a piece of software is an objective fact these defaults can be easily reviewed.
+ // This setting doesn't force the selection of any particular chain but makes validating some faster by
+ // effectively caching the result of part of the verification.
+ BlockMap::const_iterator it = mapBlockIndex.find(hashAssumeValid);
+ if (it != mapBlockIndex.end()) {
+ if (it->second->GetAncestor(pindex->nHeight) == pindex &&
+ pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
+ pindexBestHeader->nChainWork >= UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
+ // This block is a member of the assumed verified chain and an ancestor of the best header.
+ // 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
+ // that are hardly doing any signature verification at all in testing without having to
+ // artificially set the default assumed verified block further back.
+ // The test against nMinimumChainWork prevents the skipping when denied access to any chain at
+ // least as good as the expected chain.
+ fScriptChecks = (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, chainparams.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);
+ }
}
}
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]\n", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001);
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
@@ -2358,8 +1770,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash));
if (fEnforceBIP30) {
- BOOST_FOREACH(const CTransaction& tx, block.vtx) {
- const CCoins* coins = view.AccessCoins(tx.GetHash());
+ 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");
@@ -2372,15 +1784,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
- // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks,
- // when 75% of the network has upgraded:
- if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) {
+ // Start enforcing the DERSIG (BIP66) rule
+ if (pindex->nHeight >= chainparams.GetConsensus().BIP66Height) {
flags |= SCRIPT_VERIFY_DERSIG;
}
- // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4
- // blocks, when 75% of the network has upgraded:
- if (block.nVersion >= 4 && IsSuperMajority(4, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) {
+ // Start enforcing CHECKLOCKTIMEVERIFY (BIP65) rule
+ if (pindex->nHeight >= chainparams.GetConsensus().BIP65Height) {
flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
}
@@ -2394,16 +1804,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// Start enforcing WITNESS rules using versionbits logic.
if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus())) {
flags |= SCRIPT_VERIFY_WITNESS;
+ flags |= SCRIPT_VERIFY_NULLDUMMY;
}
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]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);
CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
- std::vector<uint256> vOrphanErase;
std::vector<int> prevheights;
CAmount nFees = 0;
int nInputs = 0;
@@ -2412,9 +1822,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
vPos.reserve(block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
+ std::vector<PrecomputedTransactionData> txdata;
+ txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
- const CTransaction &tx = block.vtx[i];
+ const CTransaction &tx = *(block.vtx[i]);
nInputs += tx.vin.size();
@@ -2432,17 +1844,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight;
}
- // 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);
- }
- }
-
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__),
REJECT_INVALID, "bad-txns-nonfinal");
@@ -2458,13 +1859,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
+ txdata.emplace_back(tx);
if (!tx.IsCoinBase())
{
nFees += view.GetValueIn(tx)-tx.GetValueOut();
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, nScriptCheckThreads ? &vChecks : NULL))
+ if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : NULL))
return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state));
control.Add(vChecks);
@@ -2480,19 +1882,19 @@ 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]\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);
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
- if (block.vtx[0].GetValueOut() > blockReward)
+ if (block.vtx[0]->GetValueOut() > blockReward)
return state.DoS(100,
error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)",
- block.vtx[0].GetValueOut(), blockReward),
+ block.vtx[0]->GetValueOut(), blockReward),
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]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001);
if (fJustCheck)
return true;
@@ -2501,14 +1903,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS))
{
if (pindex->GetUndoPos().IsNull()) {
- CDiskBlockPos pos;
- if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
+ CDiskBlockPos _pos;
+ if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
return error("ConnectBlock(): FindUndoPos failed");
- if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
+ if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
return AbortNode(state, "Failed to write undo data");
// update nUndoPos in block index
- pindex->nUndoPos = pos.nPos;
+ pindex->nUndoPos = _pos.nPos;
pindex->nStatus |= BLOCK_HAVE_UNDO;
}
@@ -2524,42 +1926,22 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
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();
-
- // Erase orphan transactions include or precluded by this block
- if (vOrphanErase.size()) {
- int nErased = 0;
- BOOST_FOREACH(uint256 &orphanHash, vOrphanErase) {
- nErased += EraseOrphanTx(orphanHash);
- }
- LogPrint("mempool", "Erased %d orphan tx included or conflicted by block\n", nErased);
- }
+ LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001);
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]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001);
return true;
}
-enum FlushStateMode {
- FLUSH_STATE_NONE,
- FLUSH_STATE_IF_NEEDED,
- FLUSH_STATE_PERIODIC,
- FLUSH_STATE_ALWAYS
-};
-
/**
* Update the on-disk chain state.
* The caches and indexes are flushed depending on the mode we're called with
* 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) {
+bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode, int nManualPruneHeight) {
+ int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
const CChainParams& chainparams = Params();
LOCK2(cs_main, cs_LastBlockFile);
static int64_t nLastWrite = 0;
@@ -2568,9 +1950,13 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
std::set<int> setFilesToPrune;
bool fFlushForPrune = false;
try {
- if (fPruneMode && fCheckForPruning && !fReindex) {
- FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight());
- fCheckForPruning = false;
+ 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) {
@@ -2590,11 +1976,14 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
if (nLastSetChain == 0) {
nLastSetChain = nNow;
}
- size_t cacheSize = pcoinsTip->DynamicMemoryUsage();
- // The cache is large and close to the limit, but we have time now (not in the middle of a block processing).
- bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCacheUsage;
+ int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
+ int64_t cacheSize = pcoinsTip->DynamicMemoryUsage() * DB_PEAK_USAGE_FACTOR;
+ int64_t nTotalSpace = nCoinCacheUsage + std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);
+ // The cache is large and we're within 10% and 200 MiB or 50% and 50MiB of the limit, but we have time now (not in the middle of a block processing).
+ bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize > std::min(std::max(nTotalSpace / 2, nTotalSpace - MIN_BLOCK_COINSDB_USAGE * 1024 * 1024),
+ 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 > nCoinCacheUsage;
+ 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.
@@ -2612,18 +2001,18 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
{
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]));
+ 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 (set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) {
+ 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, "Files to write to block index database");
+ return AbortNode(state, "Failed to write to block index database");
}
}
// Finally remove any pruned files
@@ -2672,7 +2061,6 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
chainActive.SetTip(pindexNew);
// New best block
- nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
cvBlockChange.notify_all();
@@ -2688,9 +2076,10 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]);
if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) {
if (state == THRESHOLD_ACTIVE) {
- strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
+ std::string strWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
+ SetMiscWarning(strWarning);
if (!fWarned) {
- AlertNotify(strMiscWarning);
+ AlertNotify(strWarning);
fWarned = true;
}
} else {
@@ -2710,10 +2099,11 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
warningMessages.push_back(strprintf("%d of last 100 blocks have unexpected version", nUpgraded));
if (nUpgraded > 100/2)
{
- // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
- strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect");
+ 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(strMiscWarning);
+ AlertNotify(strWarning);
fWarned = true;
}
}
@@ -2722,7 +2112,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
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()),
- Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
+ GuessVerificationProgress(chainParams.TxData(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
if (!warningMessages.empty())
LogPrintf(" warning='%s'", boost::algorithm::join(warningMessages, ", "));
LogPrintf("\n");
@@ -2735,18 +2125,20 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
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))
+ if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK)
return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
- assert(view.Flush());
+ 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) * 0.001);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED))
return false;
@@ -2754,12 +2146,12 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
if (!fBare) {
// Resurrect mempool transactions from the disconnected block.
std::vector<uint256> vHashUpdate;
- BOOST_FOREACH(const CTransaction &tx, block.vtx) {
+ for (const auto& it : block.vtx) {
+ const CTransaction& tx = *it;
// ignore validation errors in resurrected transactions
- list<CTransaction> removed;
CValidationState stateDummy;
- if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) {
- mempool.removeRecursive(tx, removed);
+ if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, it, false, NULL, NULL, true)) {
+ mempool.removeRecursive(tx, MemPoolRemovalReason::REORG);
} else if (mempool.exists(tx.GetHash())) {
vHashUpdate.push_back(tx.GetHash());
}
@@ -2776,9 +2168,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
UpdateTip(pindexDelete->pprev, chainparams);
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
- BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- SyncWithWallets(tx, pindexDelete->pprev, NULL);
- }
+ GetMainSignals().BlockDisconnected(pblock);
return true;
}
@@ -2788,64 +2178,127 @@ static int64_t nTimeFlush = 0;
static int64_t nTimeChainState = 0;
static int64_t nTimePostConnect = 0;
+struct PerBlockConnectTrace {
+ CBlockIndex* pindex = NULL;
+ 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.
+ */
+class ConnectTrace {
+private:
+ std::vector<PerBlockConnectTrace> blocksConnected;
+ CTxMemPool &pool;
+
+public:
+ 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
* corresponding to pindexNew, to bypass loading it again from disk.
+ *
+ * The block is added to connectTrace if connection succeeds.
*/
-bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock)
+bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace)
{
assert(pindexNew->pprev == chainActive.Tip());
// Read block from disk.
int64_t nTime1 = GetTimeMicros();
- CBlock block;
+ std::shared_ptr<const CBlock> pthisBlock;
if (!pblock) {
- if (!ReadBlockFromDisk(block, pindexNew, chainparams.GetConsensus()))
+ std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
+ if (!ReadBlockFromDisk(*pblockNew, pindexNew, chainparams.GetConsensus()))
return AbortNode(state, "Failed to read block");
- pblock = &block;
+ pthisBlock = pblockNew;
+ } else {
+ pthisBlock = pblock;
}
+ 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) * 0.001, nTimeReadFromDisk * 0.000001);
{
CCoinsViewCache view(pcoinsTip);
- bool rv = ConnectBlock(*pblock, state, pindexNew, view, chainparams);
- GetMainSignals().BlockChecked(*pblock, state);
+ bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams);
+ GetMainSignals().BlockChecked(blockConnecting, state);
if (!rv) {
if (state.IsInvalid())
InvalidBlockFound(pindexNew, state);
return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
}
- mapBlockSource.erase(pindexNew->GetBlockHash());
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
- LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
- assert(view.Flush());
+ LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
+ 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]\n", (nTime4 - nTime3) * 0.001, nTimeFlush * 0.000001);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(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);
- // Remove conflicting transactions from the mempool.
- list<CTransaction> txConflicted;
- mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload());
+ LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
+ // Remove conflicting transactions from the mempool.;
+ mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
// Update chainActive & related variables.
UpdateTip(pindexNew, chainparams);
- // Tell wallet about transactions that went from mempool
- // to conflicted:
- BOOST_FOREACH(const CTransaction &tx, txConflicted) {
- SyncWithWallets(tx, pindexNew, NULL);
- }
- // ... and about transactions that got confirmed:
- BOOST_FOREACH(const CTransaction &tx, pblock->vtx) {
- SyncWithWallets(tx, pindexNew, pblock);
- }
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]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
+ LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001);
+
+ connectTrace.BlockConnected(pindexNew, std::move(pthisBlock));
return true;
}
@@ -2923,7 +2376,7 @@ static void PruneBlockIndexCandidates() {
* Try to make some progress towards making pindexMostWork the active block.
* pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
*/
-static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound)
+static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
{
AssertLockHeld(cs_main);
const CBlockIndex *pindexOldTip = chainActive.Tip();
@@ -2956,7 +2409,7 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
// Connect new blocks.
BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
- if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) {
+ if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
if (!state.CorruptionPossible())
@@ -3002,9 +2455,8 @@ static void NotifyHeaderTip() {
CBlockIndex* pindexHeader = NULL;
{
LOCK(cs_main);
- if (!setBlockIndexCandidates.empty()) {
- pindexHeader = *setBlockIndexCandidates.rbegin();
- }
+ pindexHeader = pindexBestHeader;
+
if (pindexHeader != pindexHeaderOld) {
fNotify = true;
fInitialBlockDownload = IsInitialBlockDownload();
@@ -3022,7 +2474,12 @@ static void NotifyHeaderTip() {
* or an activated best chain. pblock is either NULL or a pointer to a block
* that is already loaded (to avoid loading it again from disk).
*/
-bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) {
+bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
+ // Note that while we're often called here from ProcessNewBlock, this is
+ // far from a guarantee. Things in the P2P/RPC will often end up calling
+ // us in the middle of ProcessNewBlock - do not assume pblock is set
+ // sanely for performance or correctness!
+
CBlockIndex *pindexMostWork = NULL;
CBlockIndex *pindexNewTip = NULL;
do {
@@ -3032,9 +2489,10 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
const CBlockIndex *pindexFork;
bool fInitialDownload;
- int nNewHeight;
{
LOCK(cs_main);
+ ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked
+
CBlockIndex *pindexOldTip = chainActive.Tip();
if (pindexMostWork == NULL) {
pindexMostWork = FindMostWorkChain();
@@ -3045,7 +2503,8 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
return true;
bool fInvalidFound = false;
- if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL, fInvalidFound))
+ std::shared_ptr<const CBlock> nullBlockPtr;
+ if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace))
return false;
if (fInvalidFound) {
@@ -3055,47 +2514,22 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
pindexNewTip = chainActive.Tip();
pindexFork = chainActive.FindFork(pindexOldTip);
fInitialDownload = IsInitialBlockDownload();
- nNewHeight = chainActive.Height();
+
+ 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
+
+ // Notify external listeners about the new tip.
+ GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
+
// Always notify the UI if a new block tip was connected
if (pindexFork != pindexNewTip) {
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
-
- if (!fInitialDownload) {
- // Find the hashes of all blocks that weren't previously in the best chain.
- std::vector<uint256> vHashes;
- CBlockIndex *pindexToAnnounce = pindexNewTip;
- while (pindexToAnnounce != pindexFork) {
- vHashes.push_back(pindexToAnnounce->GetBlockHash());
- pindexToAnnounce = pindexToAnnounce->pprev;
- if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) {
- // Limit announcements in case of a huge reorganization.
- // Rely on the peer's synchronization mechanism in that case.
- break;
- }
- }
- // Relay inventory, but don't relay old inventory during initial block download.
- int nBlockEstimate = 0;
- if (fCheckpointsEnabled)
- nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints());
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes) {
- if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) {
- BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
- pnode->PushBlockHash(hash);
- }
- }
- }
- }
- // Notify external listeners about the new tip.
- if (!vHashes.empty()) {
- GetMainSignals().UpdatedBlockTip(pindexNewTip);
- }
- }
}
} while (pindexNewTip != pindexMostWork);
CheckBlockIndex(chainparams.GetConsensus());
@@ -3105,9 +2539,42 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
return false;
}
+ int nStopAtHeight = GetArg("-stopatheight", DEFAULT_STOPATHEIGHT);
+ if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown();
+
return true;
}
+
+bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
+{
+ {
+ LOCK(cs_main);
+ if (pindex->nChainWork < chainActive.Tip()->nChainWork) {
+ // Nothing to do, this block is not at the tip.
+ return true;
+ }
+ if (chainActive.Tip()->nChainWork > nLastPreciousChainwork) {
+ // The chain has been extended since the last call, reset the counter.
+ nBlockReverseSequenceId = -1;
+ }
+ nLastPreciousChainwork = chainActive.Tip()->nChainWork;
+ setBlockIndexCandidates.erase(pindex);
+ pindex->nSequenceId = nBlockReverseSequenceId;
+ if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) {
+ // We can't keep reducing the counter if somebody really wants to
+ // call preciousblock 2**31-1 times on the same set of tips...
+ nBlockReverseSequenceId--;
+ }
+ if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && pindex->nChainTx) {
+ setBlockIndexCandidates.insert(pindex);
+ PruneBlockIndexCandidates();
+ }
+ }
+
+ return ActivateBestChain(state, params);
+}
+
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
{
AssertLockHeld(cs_main);
@@ -3144,6 +2611,7 @@ 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;
}
@@ -3195,7 +2663,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())
@@ -3204,6 +2672,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
pindexNew->BuildSkip();
}
+ 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)
@@ -3215,7 +2684,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;
@@ -3223,7 +2692,7 @@ 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);
@@ -3231,7 +2700,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
if (pindexNew->pprev == NULL || 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.
@@ -3397,22 +2866,22 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed");
// First transaction must be coinbase, the rest must not be
- if (block.vtx.empty() || !block.vtx[0].IsCoinBase())
+ if (block.vtx.empty() || !block.vtx[0]->IsCoinBase())
return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, "first tx is not coinbase");
for (unsigned int i = 1; i < block.vtx.size(); i++)
- if (block.vtx[i].IsCoinBase())
+ if (block.vtx[i]->IsCoinBase())
return state.DoS(100, false, REJECT_INVALID, "bad-cb-multiple", false, "more than one coinbase");
// Check transactions
- BOOST_FOREACH(const CTransaction& tx, block.vtx)
- if (!CheckTransaction(tx, state))
+ for (const auto& tx : block.vtx)
+ if (!CheckTransaction(*tx, state, false))
return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(),
- strprintf("Transaction check failed (tx hash %s) %s", tx.GetHash().ToString(), state.GetDebugMessage()));
+ strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
unsigned int nSigOps = 0;
- BOOST_FOREACH(const CTransaction& tx, block.vtx)
+ for (const auto& tx : block.vtx)
{
- nSigOps += GetLegacySigOpCount(tx);
+ nSigOps += GetLegacySigOpCount(*tx);
}
if (nSigOps * WITNESS_SCALE_FACTOR > MAX_BLOCK_SIGOPS_COST)
return state.DoS(100, false, REJECT_INVALID, "bad-blk-sigops", false, "out-of-bounds SigOpCount");
@@ -3429,10 +2898,12 @@ static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidati
return true;
int nHeight = pindexPrev->nHeight+1;
- // Don't accept any forks from the main chain prior to last checkpoint
+ // 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(chainparams.Checkpoints());
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
- return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
+ return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint");
return true;
}
@@ -3448,9 +2919,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;
@@ -3460,10 +2933,11 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr
{
int commitpos = GetWitnessCommitmentIndex(block);
static const std::vector<unsigned char> nonce(32, 0x00);
- if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && block.vtx[0].wit.IsEmpty()) {
- block.vtx[0].wit.vtxinwit.resize(1);
- block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.resize(1);
- block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0] = nonce;
+ if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && !block.vtx[0]->HasWitness()) {
+ CMutableTransaction tx(*block.vtx[0]);
+ tx.vin[0].scriptWitness.stack.resize(1);
+ tx.vin[0].scriptWitness.stack[0] = nonce;
+ block.vtx[0] = MakeTransactionRef(std::move(tx));
}
}
@@ -3471,15 +2945,8 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
{
std::vector<unsigned char> commitment;
int commitpos = GetWitnessCommitmentIndex(block);
- bool fHaveWitness = false;
- for (size_t t = 1; t < block.vtx.size(); t++) {
- if (!block.vtx[t].wit.IsNull()) {
- fHaveWitness = true;
- break;
- }
- }
std::vector<unsigned char> ret(32, 0x00);
- if (fHaveWitness && IsWitnessEnabled(pindexPrev, consensusParams)) {
+ 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());
@@ -3494,16 +2961,19 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
out.scriptPubKey[5] = 0xed;
memcpy(&out.scriptPubKey[6], witnessroot.begin(), 32);
commitment = std::vector<unsigned char>(out.scriptPubKey.begin(), out.scriptPubKey.end());
- const_cast<std::vector<CTxOut>*>(&block.vtx[0].vout)->push_back(out);
- block.vtx[0].UpdateHash();
+ CMutableTransaction tx(*block.vtx[0]);
+ tx.vout.push_back(out);
+ block.vtx[0] = MakeTransactionRef(std::move(tx));
}
}
UpdateUncommittedBlockStructures(block, pindexPrev, consensusParams);
return commitment;
}
-bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex * const pindexPrev, int64_t nAdjustedTime)
+bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int64_t nAdjustedTime)
{
+ assert(pindexPrev != NULL);
+ const int nHeight = pindexPrev->nHeight + 1;
// Check proof of work
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work");
@@ -3513,22 +2983,23 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
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:
- for (int32_t version = 2; version < 5; ++version) // check for version 2, 3 and 4 upgrades
- if (block.nVersion < version && IsSuperMajority(version, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
- return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", version - 1),
- strprintf("rejected nVersion=0x%08x block", version - 1));
+ // check for version 2, 3 and 4 upgrades
+ if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) ||
+ (block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) ||
+ (block.nVersion < 4 && nHeight >= consensusParams.BIP65Height))
+ return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion),
+ strprintf("rejected nVersion=0x%08x block", block.nVersion));
return true;
}
-bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex * const pindexPrev)
+bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;
- const Consensus::Params& consensusParams = Params().GetConsensus();
// Start enforcing BIP113 (Median Time Past) using versionbits logic.
int nLockTimeFlags = 0;
@@ -3541,19 +3012,18 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
: block.GetBlockTime();
// Check that all transactions are finalized
- BOOST_FOREACH(const CTransaction& tx, block.vtx) {
- if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) {
+ for (const auto& tx : block.vtx) {
+ if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) {
return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction");
}
}
- // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
- // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
- if (block.nVersion >= 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams))
+ // Enforce rule that the coinbase starts with serialized block height
+ if (nHeight >= consensusParams.BIP34Height)
{
CScript expect = CScript() << nHeight;
- if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
- !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) {
+ if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
+ !std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) {
return state.DoS(100, false, REJECT_INVALID, "bad-cb-height", false, "block height mismatch in coinbase");
}
}
@@ -3567,7 +3037,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
// {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness nonce). In case there are
// multiple, the last one is used.
bool fHaveWitness = false;
- if (IsWitnessEnabled(pindexPrev, consensusParams)) {
+ if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE) {
int commitpos = GetWitnessCommitmentIndex(block);
if (commitpos != -1) {
bool malleated = false;
@@ -3575,12 +3045,12 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
// The malleation check is ignored; as the transaction tree itself
// already does not permit it, it is impossible to trigger in the
// witness tree.
- if (block.vtx[0].wit.vtxinwit.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) {
- return state.DoS(100, error("%s : invalid witness nonce size", __func__), REJECT_INVALID, "bad-witness-nonce-size", true);
+ if (block.vtx[0]->vin[0].scriptWitness.stack.size() != 1 || block.vtx[0]->vin[0].scriptWitness.stack[0].size() != 32) {
+ return state.DoS(100, false, REJECT_INVALID, "bad-witness-nonce-size", true, strprintf("%s : invalid witness nonce size", __func__));
}
- CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin());
- if (memcmp(hashWitness.begin(), &block.vtx[0].vout[commitpos].scriptPubKey[6], 32)) {
- return state.DoS(100, error("%s : witness merkle commitment mismatch", __func__), REJECT_INVALID, "bad-witness-merkle-match", true);
+ CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0]->vin[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin());
+ if (memcmp(hashWitness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) {
+ return state.DoS(100, false, REJECT_INVALID, "bad-witness-merkle-match", true, strprintf("%s : witness merkle commitment mismatch", __func__));
}
fHaveWitness = true;
}
@@ -3589,26 +3059,26 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
// 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].wit.IsNull()) {
- return state.DoS(100, error("%s : unexpected witness data found", __func__), REJECT_INVALID, "unexpected-witness", true);
+ if (block.vtx[i]->HasWitness()) {
+ return state.DoS(100, false, REJECT_INVALID, "unexpected-witness", true, strprintf("%s : unexpected witness data found", __func__));
}
}
}
// After the coinbase witness nonce and commitment are verified,
- // we can check if the block cost passes (before we've checked the
- // coinbase witness, it would be possible for the cost to be too
+ // we can check if the block weight passes (before we've checked the
+ // coinbase witness, it would be possible for the weight to be too
// large by filling up the coinbase witness, which doesn't change
// the block hash, so we couldn't mark the block as permanently
// failed).
- if (GetBlockCost(block) > MAX_BLOCK_COST) {
- return state.DoS(100, error("ContextualCheckBlock(): cost limit failed"), REJECT_INVALID, "bad-blk-cost");
+ if (GetBlockWeight(block) > MAX_BLOCK_WEIGHT) {
+ return state.DoS(100, false, REJECT_INVALID, "bad-blk-weight", false, strprintf("%s : weight limit failed", __func__));
}
return true;
}
-static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL)
+static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
{
AssertLockHeld(cs_main);
// Check for duplicate
@@ -3634,7 +3104,7 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
CBlockIndex* pindexPrev = NULL;
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end())
- return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk");
+ 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");
@@ -3652,12 +3122,35 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
if (ppindex)
*ppindex = pindex;
+ CheckBlockIndex(chainparams.GetConsensus());
+
+ return true;
+}
+
+// Exposed wrapper for AcceptBlockHeader
+bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex)
+{
+ {
+ LOCK(cs_main);
+ for (const CBlockHeader& header : headers) {
+ CBlockIndex *pindex = NULL; // Use a temp pindex instead of ppindex to avoid a const_cast
+ if (!AcceptBlockHeader(header, state, chainparams, &pindex)) {
+ return false;
+ }
+ if (ppindex) {
+ *ppindex = pindex;
+ }
+ }
+ }
+ NotifyHeaderTip();
return true;
}
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
-static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
+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;
+
if (fNewBlock) *fNewBlock = false;
AssertLockHeld(cs_main);
@@ -3679,6 +3172,11 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
// not process unrequested blocks.
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 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.
+
// TODO: deal better with return value and error conditions for duplicate
// and unrequested blocks.
if (fAlreadyHave) return true;
@@ -3689,7 +3187,8 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
}
if (fNewBlock) *fNewBlock = true;
- if ((!CheckBlock(block, state, chainparams.GetConsensus(), GetAdjustedTime())) || !ContextualCheckBlock(block, state, pindex->pprev)) {
+ if (!CheckBlock(block, state, chainparams.GetConsensus()) ||
+ !ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) {
if (state.IsInvalid() && !state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
@@ -3697,6 +3196,11 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
return error("%s: %s", __func__, FormatStateMessage(state));
}
+ // Header is valid/has work, merkle tree and segwit merkle tree are good...RELAY NOW
+ // (but if it does not build on our best tip, let the SendMessages loop relay it)
+ if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev)
+ GetMainSignals().NewPoWValidBlock(pindex, pblock);
+
int nHeight = pindex->nHeight;
// Write block to history file
@@ -3710,7 +3214,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
if (dbp == NULL)
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());
@@ -3722,41 +3226,32 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
return true;
}
-static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams)
+bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool *fNewBlock)
{
- unsigned int nFound = 0;
- for (int i = 0; i < consensusParams.nMajorityWindow && nFound < nRequired && pstart != NULL; i++)
{
- if (pstart->nVersion >= minVersion)
- ++nFound;
- pstart = pstart->pprev;
- }
- return (nFound >= nRequired);
-}
-
+ CBlockIndex *pindex = NULL;
+ if (fNewBlock) *fNewBlock = false;
+ CValidationState state;
+ // Ensure that CheckBlock() passes before calling AcceptBlock, as
+ // belt-and-suspenders.
+ bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus());
-bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp)
-{
- {
LOCK(cs_main);
- bool fRequested = MarkBlockAsReceived(pblock->GetHash());
- fRequested |= fForceProcessing;
- // Store to disk
- CBlockIndex *pindex = NULL;
- bool fNewBlock = false;
- bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fRequested, dbp, &fNewBlock);
- if (pindex && pfrom) {
- mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
- if (fNewBlock) pfrom->nLastBlockTime = GetTime();
+ if (ret) {
+ // Store to disk
+ ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, NULL, fNewBlock);
}
CheckBlockIndex(chainparams.GetConsensus());
- if (!ret)
+ if (!ret) {
+ GetMainSignals().BlockChecked(*pblock, state);
return error("%s: AcceptBlock FAILED", __func__);
+ }
}
NotifyHeaderTip();
+ CValidationState state; // Only used to report errors, not invalidity - ignore it
if (!ActivateBestChain(state, chainparams, pblock))
return error("%s: ActivateBestChain failed", __func__);
@@ -3780,7 +3275,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
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));
- if (!ContextualCheckBlock(block, state, pindexPrev))
+ if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev))
return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state));
if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
return false;
@@ -3822,10 +3317,10 @@ void PruneOneBlockFile(const int fileNumber)
// mapBlocksUnlinked or setBlockIndexCandidates.
std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex->pprev);
while (range.first != range.second) {
- std::multimap<CBlockIndex *, CBlockIndex *>::iterator it = range.first;
+ std::multimap<CBlockIndex *, CBlockIndex *>::iterator _it = range.first;
range.first++;
- if (it->second == pindex) {
- mapBlocksUnlinked.erase(it);
+ if (_it->second == pindex) {
+ mapBlocksUnlinked.erase(_it);
}
}
}
@@ -3836,16 +3331,45 @@ 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)
+{
+ assert(fPruneMode && nManualPruneHeight > 0);
+
+ LOCK2(cs_main, cs_LastBlockFile);
+ if (chainActive.Tip() == NULL)
+ return;
+
+ // last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip)
+ 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)
+ continue;
+ PruneOneBlockFile(fileNumber);
+ setFilesToPrune.insert(fileNumber);
+ count++;
+ }
+ LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", nLastBlockWeCanPrune, count);
+}
+
+/* This function is called from the RPC code for pruneblockchain */
+void PruneBlockFilesManual(int nManualPruneHeight)
+{
+ CValidationState state;
+ FlushStateToDisk(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)
{
@@ -3888,7 +3412,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);
@@ -3896,7 +3420,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)
@@ -3909,11 +3433,11 @@ 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+");
+ 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;
@@ -3936,7 +3460,7 @@ 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);
}
@@ -3954,34 +3478,34 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
// Create new
CBlockIndex* pindexNew = new CBlockIndex();
if (!pindexNew)
- throw runtime_error("LoadBlockIndex(): 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;
}
-bool static LoadBlockIndexDB()
+bool static LoadBlockIndexDB(const CChainParams& chainparams)
{
- const CChainParams& chainparams = Params();
if (!pblocktree->LoadBlockIndexGuts(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)
{
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)
{
CBlockIndex* pindex = item.second;
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
+ pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
// We can link the chain of blocks for which we've received transactions at some point.
// Pruned nodes may have deleted the block.
if (pindex->nTx > 0) {
@@ -4025,7 +3549,7 @@ bool static LoadBlockIndexDB()
// Check presence of blk files
LogPrintf("Checking all blk files are present...\n");
- set<int> setBlkDataFiles;
+ std::set<int> setBlkDataFiles;
BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
{
CBlockIndex* pindex = item.second;
@@ -4066,7 +3590,7 @@ bool static LoadBlockIndexDB()
LogPrintf("%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__,
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(),
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
- Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.Tip()));
+ GuessVerificationProgress(chainparams.TxData(), chainActive.Tip()));
return true;
}
@@ -4100,7 +3624,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
int nGoodTransactions = 0;
CValidationState state;
int reportDone = 0;
- LogPrintf("[0%]...");
+ LogPrintf("[0%%]...");
for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
{
boost::this_thread::interruption_point();
@@ -4124,7 +3648,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) {
@@ -4137,15 +3661,17 @@ 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))
+ 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;
@@ -4258,6 +3784,9 @@ bool RewindBlockIndex(const CChainParams& params)
return true;
}
+// May NOT be used after any connections are up as much
+// of the peer-processing logic assumes a consistent
+// block index state
void UnloadBlockIndex()
{
LOCK(cs_main);
@@ -4266,20 +3795,12 @@ void UnloadBlockIndex()
pindexBestInvalid = NULL;
pindexBestHeader = NULL;
mempool.clear();
- mapOrphanTransactions.clear();
- mapOrphanTransactionsByPrev.clear();
- nSyncStarted = 0;
mapBlocksUnlinked.clear();
vinfoBlockFile.clear();
nLastBlockFile = 0;
nBlockSequenceId = 1;
- mapBlockSource.clear();
- mapBlocksInFlight.clear();
- nPreferredDownload = 0;
setDirtyBlockIndex.clear();
setDirtyFileInfo.clear();
- mapNodeState.clear();
- recentRejects.reset(NULL);
versionbitscache.Clear();
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
warningcache[b].clear();
@@ -4292,21 +3813,18 @@ void UnloadBlockIndex()
fHavePruned = false;
}
-bool LoadBlockIndex()
+bool LoadBlockIndex(const CChainParams& chainparams)
{
// Load block index from databases
- if (!fReindex && !LoadBlockIndexDB())
+ if (!fReindex && !LoadBlockIndexDB(chainparams))
return false;
return true;
}
-bool InitBlockIndex(const CChainParams& chainparams)
+bool InitBlockIndex(const CChainParams& chainparams)
{
LOCK(cs_main);
- // Initialize global variables that cannot be constructed at startup.
- recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
-
// Check whether we're already initialized
if (chainActive.Genesis() != NULL)
return true;
@@ -4329,10 +3847,8 @@ bool InitBlockIndex(const CChainParams& chainparams)
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))
+ if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
return error("LoadBlockIndex(): genesis block not accepted");
- if (!ActivateBestChain(state, chainparams, &block))
- return error("LoadBlockIndex(): genesis block cannot be activated");
// 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) {
@@ -4363,11 +3879,11 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
unsigned int nSize = 0;
try {
// locate a header
- unsigned char buf[MESSAGE_START_SIZE];
+ unsigned char buf[CMessageHeader::MESSAGE_START_SIZE];
blkdat.FindByte(chainparams.MessageStart()[0]);
nRewind = blkdat.GetPos()+1;
blkdat >> FLATDATA(buf);
- if (memcmp(buf, chainparams.MessageStart(), MESSAGE_START_SIZE))
+ if (memcmp(buf, chainparams.MessageStart(), CMessageHeader::MESSAGE_START_SIZE))
continue;
// read size
blkdat >> nSize;
@@ -4384,14 +3900,15 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
dbp->nPos = nBlockPos;
blkdat.SetLimit(nBlockPos + nSize);
blkdat.SetPos(nBlockPos);
- CBlock block;
+ std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
+ CBlock& block = *pblock;
blkdat >> block;
nRewind = blkdat.GetPos();
// 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));
@@ -4402,12 +3919,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(block, state, chainparams, NULL, true, dbp, NULL))
+ if (AcceptBlock(pblock, state, chainparams, NULL, true, dbp, NULL))
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
@@ -4421,7 +3938,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();
@@ -4429,16 +3946,17 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
std::pair<std::multimap<uint256, CDiskBlockPos>::iterator, std::multimap<uint256, CDiskBlockPos>::iterator> range = mapBlocksUnknownParent.equal_range(head);
while (range.first != range.second) {
std::multimap<uint256, CDiskBlockPos>::iterator it = range.first;
- if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus()))
+ 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__, block.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(block, dummy, chainparams, NULL, true, &it->second, NULL))
+ if (AcceptBlock(pblockrecursive, dummy, chainparams, NULL, true, &it->second, NULL))
{
nLoaded++;
- queue.push_back(block.GetHash());
+ queue.push_back(pblockrecursive->GetHash());
}
}
range.first++;
@@ -4515,7 +4033,7 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
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.
}
- if (pindex->nChainTx == 0) assert(pindex->nSequenceId == 0); // nSequenceId can't be set for blocks that aren't linked
+ if (pindex->nChainTx == 0) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
// VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).
// HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
if (!fHavePruned) {
@@ -4642,2157 +4160,158 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
assert(nNodes == forward.size());
}
-std::string GetWarnings(const std::string& strFor)
+std::string CBlockFileInfo::ToString() const
{
- string strStatusBar;
- string strRPC;
- string strGUI;
-
- if (!CLIENT_VERSION_IS_RELEASE) {
- strStatusBar = "This is a pre-release test build - use at your own risk - do not use for mining or merchant applications";
- 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))
- strStatusBar = strRPC = strGUI = "testsafemode enabled";
-
- // Misc warnings like out of disk space and clock is wrong
- if (strMiscWarning != "")
- {
- strStatusBar = strGUI = strMiscWarning;
- }
-
- if (fLargeWorkForkFound)
- {
- strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
- strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
- }
- else if (fLargeWorkInvalidChainFound)
- {
- strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
- strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
- }
-
- if (strFor == "gui")
- return strGUI;
- else if (strFor == "statusbar")
- return strStatusBar;
- else if (strFor == "rpc")
- return strRPC;
- assert(!"GetWarnings(): invalid parameter");
- return "error";
+ 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));
}
-
-
-
-
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Messages
-//
-
-
-bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+CBlockFileInfo* GetBlockFileInfo(size_t n)
{
- switch (inv.type)
- {
- case MSG_TX:
- case MSG_WITNESS_TX:
- {
- assert(recentRejects);
- if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip)
- {
- // If the chain tip has changed previously rejected transactions
- // might be now valid, e.g. due to a nLockTime'd tx becoming valid,
- // or a double-spend. Reset the rejects filter and give those
- // txs a second chance.
- hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash();
- recentRejects->reset();
- }
-
- // 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);
- }
- case MSG_BLOCK:
- case MSG_WITNESS_BLOCK:
- return mapBlockIndex.count(inv.hash);
- }
- // Don't know what it is, just say we already got one
- return true;
+ return &vinfoBlockFile.at(n);
}
-void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams)
+ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
- std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
-
- vector<CInv> vNotFound;
-
LOCK(cs_main);
-
- while (it != pfrom->vRecvGetData.end()) {
- // Don't bother if send buffer is too full to respond anyway
- if (pfrom->nSendSize >= SendBufferSize())
- break;
-
- const CInv &inv = *it;
- {
- boost::this_thread::interruption_point();
- it++;
-
- if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK)
- {
- bool send = false;
- BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
- if (mi != mapBlockIndex.end())
- {
- if (chainActive.Contains(mi->second)) {
- send = true;
- } else {
- static const int nOneMonth = 30 * 24 * 60 * 60;
- // 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) &&
- (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) &&
- (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensusParams) < nOneMonth);
- if (!send) {
- LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId());
- }
- }
- }
- // 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 && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (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());
-
- //disconnect node
- pfrom->fDisconnect = true;
- send = false;
- }
- // Pruned nodes may have deleted the block, so check whether
- // 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");
- if (inv.type == MSG_BLOCK)
- pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
- else if (inv.type == MSG_WITNESS_BLOCK)
- pfrom->PushMessage(NetMsgType::BLOCK, block);
- else if (inv.type == MSG_FILTERED_BLOCK)
- {
- LOCK(pfrom->cs_filter);
- if (pfrom->pfilter)
- {
- CMerkleBlock merkleBlock(block, *pfrom->pfilter);
- pfrom->PushMessage(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 -
- // they must either disconnect and retry or request the full block.
- // 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)
- pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, block.vtx[pair.first]);
- }
- // else
- // no response
- }
- else if (inv.type == MSG_CMPCT_BLOCK)
- {
- // If a peer is asking for old blocks, we're almost guaranteed
- // they wont have a useful mempool to match against a compact block,
- // and we dont feel like constructing the object for them, so
- // instead we respond with the full, non-compact block.
- if (mi->second->nHeight >= chainActive.Height() - 10) {
- CBlockHeaderAndShortTxIDs cmpctblock(block);
- pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
- } else
- pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
- }
-
- // Trigger the peer node to send a getblocks request for the next batch of inventory
- if (inv.hash == pfrom->hashContinue)
- {
- // 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;
- vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash()));
- pfrom->PushMessage(NetMsgType::INV, vInv);
- pfrom->hashContinue.SetNull();
- }
- }
- }
- else if (inv.type == MSG_TX || inv.type == MSG_WITNESS_TX)
- {
- // Send stream from relay memory
- bool push = false;
- auto mi = mapRelay.find(inv.hash);
- if (mi != mapRelay.end()) {
- pfrom->PushMessageWithFlag(inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0, 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) {
- pfrom->PushMessageWithFlag(inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0, NetMsgType::TX, *txinfo.tx);
- push = true;
- }
- }
- if (!push) {
- vNotFound.push_back(inv);
- }
- }
-
- // Track requests for our stuff.
- GetMainSignals().Inventory(inv.hash);
-
- if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK)
- break;
- }
- }
-
- pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it);
-
- if (!vNotFound.empty()) {
- // Let the peer know that we didn't find what it asked for, so it doesn't
- // have to wait around forever. Currently only SPV clients actually care
- // about this message: it's needed when they are recursively walking the
- // dependencies of relevant unconfirmed transactions. SPV clients want to
- // 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.
- pfrom->PushMessage(NetMsgType::NOTFOUND, vNotFound);
- }
-}
-
-uint32_t GetFetchFlags(CNode* pfrom, CBlockIndex* pprev, const Consensus::Params& chainparams) {
- uint32_t nFetchFlags = 0;
- if (IsWitnessEnabled(pprev, chainparams) && State(pfrom->GetId())->fHaveWitness) {
- nFetchFlags |= MSG_WITNESS_FLAG;
- }
- return nFetchFlags;
+ return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);
}
-bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams)
+int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
- LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
- if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
- {
- LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n");
- return true;
- }
-
-
- if (!(nLocalServices & NODE_BLOOM) &&
- (strCommand == NetMsgType::FILTERLOAD ||
- strCommand == NetMsgType::FILTERADD ||
- strCommand == NetMsgType::FILTERCLEAR))
- {
- if (pfrom->nVersion >= NO_BLOOM_VERSION) {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 100);
- return false;
- } else {
- pfrom->fDisconnect = true;
- return false;
- }
- }
-
-
- if (strCommand == NetMsgType::VERSION)
- {
- // Each connection can only send one version message
- if (pfrom->nVersion != 0)
- {
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 1);
- return false;
- }
-
- int64_t nTime;
- CAddress addrMe;
- CAddress addrFrom;
- uint64_t nNonce = 1;
- uint64_t nServiceInt;
- vRecv >> pfrom->nVersion >> nServiceInt >> nTime >> addrMe;
- pfrom->nServices = ServiceFlags(nServiceInt);
- if (!pfrom->fInbound)
- {
- addrman.SetServices(pfrom->addr, pfrom->nServices);
- }
- if (pfrom->nServicesExpected & ~pfrom->nServices)
- {
- LogPrint("net", "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->id, pfrom->nServices, pfrom->nServicesExpected);
- pfrom->PushMessage(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)
- {
- // disconnect from peers older than this proto version
- LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion);
- pfrom->PushMessage(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 (!vRecv.empty())
- vRecv >> addrFrom >> nNonce;
- if (!vRecv.empty()) {
- vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH);
- pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer);
- }
- if (!vRecv.empty()) {
- vRecv >> pfrom->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;
- }
-
- // Disconnect if we connected to ourself
- if (nNonce == nLocalHostNonce && nNonce > 1)
- {
- 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);
- }
-
- // Be shy and don't send version until we hear
- if (pfrom->fInbound)
- pfrom->PushVersion();
-
- pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
-
- if((pfrom->nServices & NODE_WITNESS))
- {
- LOCK(cs_main);
- State(pfrom->GetId())->fHaveWitness = true;
- }
-
- // Potentially mark this peer as a preferred download peer.
- {
- LOCK(cs_main);
- UpdatePreferredDownload(pfrom, State(pfrom->GetId()));
- }
-
- // Change version
- pfrom->PushMessage(NetMsgType::VERACK);
- pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
-
- if (!pfrom->fInbound)
- {
- // Advertise our address
- if (fListen && !IsInitialBlockDownload())
- {
- CAddress addr = GetLocalAddress(&pfrom->addr);
- if (addr.IsRoutable())
- {
- LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
- pfrom->PushAddress(addr);
- } else if (IsPeerAddrLocalGood(pfrom)) {
- addr.SetIP(pfrom->addrLocal);
- LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
- pfrom->PushAddress(addr);
- }
- }
-
- // Get recent addresses
- if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
- {
- pfrom->PushMessage(NetMsgType::GETADDR);
- pfrom->fGetAddr = true;
- }
- addrman.Good(pfrom->addr);
- } else {
- if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom)
- {
- addrman.Add(addrFrom, addrFrom);
- addrman.Good(addrFrom);
- }
- }
-
- pfrom->fSuccessfullyConnected = true;
-
- 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,
- remoteAddr);
-
- int64_t nTimeOffset = nTime - GetTime();
- pfrom->nTimeOffset = nTimeOffset;
- AddTimeData(pfrom->addr, nTimeOffset);
- }
+ LOCK(cs_main);
+ return VersionBitsStateSinceHeight(chainActive.Tip(), params, pos, versionbitscache);
+}
+static const uint64_t MEMPOOL_DUMP_VERSION = 1;
- else if (pfrom->nVersion == 0)
- {
- // Must have a version message before anything else
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 1);
+bool LoadMempool(void)
+{
+ int64_t nExpiryTimeout = 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");
return false;
}
+ int64_t count = 0;
+ int64_t skipped = 0;
+ int64_t failed = 0;
+ int64_t nNow = GetTime();
- else if (strCommand == NetMsgType::VERACK)
- {
- pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
-
- // Mark this node as currently connected, so we update its timestamp later.
- if (pfrom->fNetworkNode) {
- LOCK(cs_main);
- State(pfrom->GetId())->fCurrentlyConnected = true;
- }
-
- if (pfrom->nVersion >= SENDHEADERS_VERSION) {
- // Tell our peer we prefer to receive headers rather than inv's
- // We send this to non-NODE NETWORK peers as well, because even
- // non-NODE NETWORK peers can announce blocks (such as pruning
- // nodes)
- pfrom->PushMessage(NetMsgType::SENDHEADERS);
- }
- if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) {
- // Tell our peer we are willing to provide version-1 cmpctblocks
- // However, we do not request new block announcements using
- // cmpctblock messages.
- // We send this to non-NODE NETWORK peers as well, because
- // they may wish to request compact blocks from us
- bool fAnnounceUsingCMPCTBLOCK = false;
- uint64_t nCMPCTBLOCKVersion = 1;
- pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
- }
- }
-
-
- else if (strCommand == NetMsgType::ADDR)
- {
- vector<CAddress> vAddr;
- vRecv >> vAddr;
-
- // Don't want addr from older versions unless seeding
- if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000)
- return true;
- if (vAddr.size() > 1000)
- {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 20);
- return error("message addr size() = %u", vAddr.size());
- }
-
- // Store the new addresses
- vector<CAddress> vAddrOk;
- int64_t nNow = GetAdjustedTime();
- int64_t nSince = nNow - 10 * 60;
- BOOST_FOREACH(CAddress& addr, vAddr)
- {
- boost::this_thread::interruption_point();
-
- if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)
- continue;
-
- if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
- addr.nTime = nNow - 5 * 24 * 60 * 60;
- pfrom->AddAddressKnown(addr);
- bool fReachable = IsReachable(addr);
- if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
- {
- // Relay to a limited number of other nodes
- {
- LOCK(cs_vNodes);
- // Use deterministic randomness to send to the same nodes for 24 hours
- // at a time so the addrKnowns of the chosen nodes prevent repeats
- static const uint64_t salt0 = GetRand(std::numeric_limits<uint64_t>::max());
- static const uint64_t salt1 = GetRand(std::numeric_limits<uint64_t>::max());
- uint64_t hashAddr = addr.GetHash();
- multimap<uint64_t, CNode*> mapMix;
- const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
- BOOST_FOREACH(CNode* pnode, vNodes)
- {
- if (pnode->nVersion < CADDR_TIME_VERSION)
- continue;
- uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
- mapMix.insert(make_pair(hashKey, pnode));
- }
- int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
- for (multimap<uint64_t, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
- ((*mi).second)->PushAddress(addr);
- }
- }
- // Do not store addresses outside our network
- if (fReachable)
- vAddrOk.push_back(addr);
- }
- addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60);
- if (vAddr.size() < 1000)
- pfrom->fGetAddr = false;
- if (pfrom->fOneShot)
- pfrom->fDisconnect = true;
- }
-
- else if (strCommand == NetMsgType::SENDHEADERS)
- {
- LOCK(cs_main);
- State(pfrom->GetId())->fPreferHeaders = true;
- }
-
- else if (strCommand == NetMsgType::SENDCMPCT)
- {
- bool fAnnounceUsingCMPCTBLOCK = false;
- uint64_t nCMPCTBLOCKVersion = 1;
- vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
- if (nCMPCTBLOCKVersion == 1) {
- LOCK(cs_main);
- State(pfrom->GetId())->fProvidesHeaderAndIDs = true;
- State(pfrom->GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK;
- }
- }
-
-
- else if (strCommand == NetMsgType::INV)
- {
- vector<CInv> vInv;
- vRecv >> vInv;
- if (vInv.size() > MAX_INV_SZ)
- {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 20);
- return error("message inv size() = %u", vInv.size());
- }
-
- 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))
- fBlocksOnly = false;
-
- LOCK(cs_main);
-
- uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus());
-
- std::vector<CInv> vToFetch;
-
- for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
- {
- CInv &inv = vInv[nInv];
-
- boost::this_thread::interruption_point();
-
- bool fAlreadyHave = AlreadyHave(inv);
- LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id);
-
- if (inv.type == MSG_TX) {
- inv.type |= nFetchFlags;
- }
-
- if (inv.type == MSG_BLOCK) {
- UpdateBlockAvailability(pfrom->GetId(), inv.hash);
- if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
- // First request the headers preceding the announced block. In the normal fully-synced
- // case where a new block is announced that succeeds the current tip (no reorganization),
- // there are no such headers.
- // Secondly, and only when we are close to being synced, we request the announced block directly,
- // to avoid an extra round-trip. Note that we must *first* ask for the headers, so by the
- // time the block arrives, the header chain leading up to it is already validated. Not
- // doing this will result in the received block being rejected as an orphan in case it is
- // not a direct successor.
- pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash);
- CNodeState *nodestate = State(pfrom->GetId());
- if (CanDirectFetch(chainparams.GetConsensus()) &&
- nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER &&
- (!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
- inv.type |= nFetchFlags;
- if (nodestate->fProvidesHeaderAndIDs && !(nLocalServices & NODE_WITNESS))
- vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash));
- else
- vToFetch.push_back(inv);
- // Mark block as in flight already, even though the actual "getdata" message only goes out
- // later (within the same cs_main lock, though).
- MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus());
- }
- LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id);
- }
- }
- 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())
- pfrom->AskFor(inv);
- }
-
- // Track requests for our stuff
- GetMainSignals().Inventory(inv.hash);
-
- if (pfrom->nSendSize > (SendBufferSize() * 2)) {
- Misbehaving(pfrom->GetId(), 50);
- return error("send buffer size() = %u", pfrom->nSendSize);
- }
- }
-
- if (!vToFetch.empty())
- pfrom->PushMessage(NetMsgType::GETDATA, vToFetch);
- }
-
-
- else if (strCommand == NetMsgType::GETDATA)
- {
- vector<CInv> vInv;
- vRecv >> vInv;
- if (vInv.size() > MAX_INV_SZ)
- {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 20);
- 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);
-
- if ((fDebug && vInv.size() > 0) || (vInv.size() == 1))
- LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id);
-
- pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());
- ProcessGetData(pfrom, chainparams.GetConsensus());
- }
-
-
- else if (strCommand == NetMsgType::GETBLOCKS)
- {
- CBlockLocator locator;
- uint256 hashStop;
- vRecv >> locator >> hashStop;
-
- LOCK(cs_main);
-
- // Find the last block the caller has in the main chain
- CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator);
-
- // Send the rest of the chain
- 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);
- for (; pindex; pindex = chainActive.Next(pindex))
- {
- if (pindex->GetBlockHash() == hashStop)
- {
- LogPrint("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
- // for some reasonable time window (1 hour) that block relay might require.
- 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());
- break;
- }
- pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
- if (--nLimit <= 0)
- {
- // 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());
- pfrom->hashContinue = pindex->GetBlockHash();
- break;
- }
- }
- }
-
-
- else if (strCommand == NetMsgType::GETBLOCKTXN)
- {
- BlockTransactionsRequest req;
- vRecv >> req;
-
- BlockMap::iterator it = mapBlockIndex.find(req.blockhash);
- if (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)) {
- Misbehaving(pfrom->GetId(), 100);
- LogPrintf("Peer %d sent us a getblocktxn for a block we don't have", pfrom->id);
- return true;
- }
-
- if (it->second->nHeight < chainActive.Height() - 15) {
- LogPrint("net", "Peer %d sent us a getblocktxn for a block > 15 deep", pfrom->id);
- return true;
- }
-
- CBlock block;
- assert(ReadBlockFromDisk(block, it->second, chainparams.GetConsensus()));
-
- BlockTransactions resp(req);
- for (size_t i = 0; i < req.indexes.size(); i++) {
- if (req.indexes[i] >= block.vtx.size()) {
- Misbehaving(pfrom->GetId(), 100);
- LogPrintf("Peer %d sent us a getblocktxn with out-of-bounds tx indices", pfrom->id);
- return true;
- }
- resp.txn[i] = block.vtx[req.indexes[i]];
- }
- pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCKTXN, resp);
- }
-
-
- else if (strCommand == NetMsgType::GETHEADERS)
- {
- CBlockLocator locator;
- uint256 hashStop;
- vRecv >> locator >> hashStop;
-
- LOCK(cs_main);
- if (IsInitialBlockDownload() && !pfrom->fWhitelisted) {
- LogPrint("net", "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->id);
- return true;
- }
-
- CNodeState *nodestate = State(pfrom->GetId());
- CBlockIndex* pindex = NULL;
- if (locator.IsNull())
- {
- // If locator is null, return the hashStop block
- BlockMap::iterator mi = mapBlockIndex.find(hashStop);
- if (mi == mapBlockIndex.end())
- return true;
- pindex = (*mi).second;
- }
- else
- {
- // Find the last block the caller has in the main chain
- pindex = FindForkInGlobalIndex(chainActive, locator);
- if (pindex)
- pindex = chainActive.Next(pindex);
- }
-
- // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
- vector<CBlock> vHeaders;
- int nLimit = MAX_HEADERS_RESULTS;
- LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id);
- 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
- // 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.
- nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
- pfrom->PushMessage(NetMsgType::HEADERS, vHeaders);
- }
-
-
- else if (strCommand == NetMsgType::TX)
- {
- // 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)))
- {
- LogPrint("net", "transaction sent in violation of protocol peer=%d\n", pfrom->id);
- return true;
- }
-
- deque<COutPoint> vWorkQueue;
- vector<uint256> vEraseQueue;
- CTransaction tx;
- vRecv >> tx;
-
- CInv inv(MSG_TX, tx.GetHash());
- pfrom->AddInventoryKnown(inv);
-
- LOCK(cs_main);
-
- bool fMissingInputs = false;
- CValidationState state;
-
- pfrom->setAskFor.erase(inv.hash);
- mapAlreadyAskedFor.erase(inv.hash);
-
- if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) {
- mempool.check(pcoinsTip);
- RelayTransaction(tx);
- for (unsigned int i = 0; i < tx.vout.size(); i++) {
- vWorkQueue.emplace_back(inv.hash, i);
- }
-
- pfrom->nLastTXTime = GetTime();
-
- LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
- pfrom->id,
- tx.GetHash().ToString(),
- mempool.size(), mempool.DynamicMemoryUsage() / 1000);
-
- // Recursively process any orphan transactions that depended on this one
- set<NodeId> setMisbehaving;
- while (!vWorkQueue.empty()) {
- auto itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue.front());
- vWorkQueue.pop_front();
- 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();
- NodeId fromPeer = (*mi)->second.fromPeer;
- bool fMissingInputs2 = false;
- // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
- // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
- // anyone relaying LegitTxX banned)
- CValidationState stateDummy;
-
-
- if (setMisbehaving.count(fromPeer))
- continue;
- if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) {
- LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanTx);
- for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
- vWorkQueue.emplace_back(orphanHash, i);
- }
- vEraseQueue.push_back(orphanHash);
- }
- else if (!fMissingInputs2)
- {
- int nDos = 0;
- if (stateDummy.IsInvalid(nDos) && nDos > 0 && (!state.CorruptionPossible() || State(fromPeer)->fHaveWitness))
- {
- // Punish peer that gave us an invalid orphan tx
- Misbehaving(fromPeer, nDos);
- setMisbehaving.insert(fromPeer);
- LogPrint("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());
- vEraseQueue.push_back(orphanHash);
- if (!stateDummy.CorruptionPossible()) {
- assert(recentRejects);
- recentRejects->insert(orphanHash);
- }
- }
- mempool.check(pcoinsTip);
- }
- }
-
- BOOST_FOREACH(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) {
- if (recentRejects->contains(txin.prevout.hash)) {
- fRejectedParents = true;
- break;
- }
- }
- if (!fRejectedParents) {
- BOOST_FOREACH(const CTxIn& txin, tx.vin) {
- CInv inv(MSG_TX, txin.prevout.hash);
- pfrom->AddInventoryKnown(inv);
- if (!AlreadyHave(inv)) pfrom->AskFor(inv);
- }
- AddOrphanTx(tx, 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 nEvicted = LimitOrphanTxSize(nMaxOrphanTx);
- if (nEvicted > 0)
- LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted);
- } else {
- LogPrint("mempool", "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
- }
- } else {
- if (!state.CorruptionPossible()) {
- assert(recentRejects);
- recentRejects->insert(tx.GetHash());
- }
-
- if (pfrom->fWhitelisted && 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
- // nodes hidden behind it.
- //
- // Never relay transactions that we would assign a non-zero DoS
- // score for, as we expect peers to do the same with us in that
- // 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);
- RelayTransaction(tx);
- } else {
- LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
- }
- }
- }
- int nDoS = 0;
- if (state.IsInvalid(nDoS))
- {
- LogPrint("mempoolrej", "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
- pfrom->id,
- FormatStateMessage(state));
- if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
- state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
- if (nDoS > 0 && (!state.CorruptionPossible() || State(pfrom->id)->fHaveWitness)) {
- // When a non-witness-supporting peer gives us a transaction that would
- // be accepted if witness validation was off, we can't blame them for it.
- Misbehaving(pfrom->GetId(), nDoS);
- }
- }
- FlushStateToDisk(state, FLUSH_STATE_PERIODIC);
- }
-
-
- else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
- {
- CBlockHeaderAndShortTxIDs cmpctblock;
- vRecv >> cmpctblock;
-
- LOCK(cs_main);
-
- if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) {
- // Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
- if (!IsInitialBlockDownload())
- pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256());
- return true;
- }
-
- CBlockIndex *pindex = NULL;
- CValidationState state;
- if (!AcceptBlockHeader(cmpctblock.header, state, chainparams, &pindex)) {
- int nDoS;
- if (state.IsInvalid(nDoS)) {
- if (nDoS > 0)
- Misbehaving(pfrom->GetId(), nDoS);
- LogPrintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->id);
- return true;
- }
- }
-
- // If AcceptBlockHeader returned true, it set pindex
- assert(pindex);
- UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHash());
-
- std::map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator blockInFlightIt = mapBlocksInFlight.find(pindex->GetBlockHash());
- bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end();
-
- if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here
- return true;
-
- if (pindex->nChainWork <= chainActive.Tip()->nChainWork || // We know something better
- pindex->nTx != 0) { // We had this block at some point, but pruned it
- if (fAlreadyInFlight) {
- // 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, cmpctblock.header.GetHash());
- pfrom->PushMessage(NetMsgType::GETDATA, vInv);
- return true;
- }
- }
-
- // If we're not close to tip yet, give up and let parallel block fetch work its magic
- if (!fAlreadyInFlight && !CanDirectFetch(chainparams.GetConsensus()))
- return true;
-
- CNodeState *nodestate = State(pfrom->GetId());
-
- // We want to be a bit conservative just to be extra careful about DoS
- // possibilities in compact block processing...
- 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)) {
- 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");
- return true;
- }
- }
-
- PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
- ReadStatus status = partialBlock.InitData(cmpctblock);
- 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);
- 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, cmpctblock.header.GetHash());
- pfrom->PushMessage(NetMsgType::GETDATA, vInv);
- return true;
- }
-
- BlockTransactionsRequest req;
- for (size_t i = 0; i < cmpctblock.BlockTxCount(); i++) {
- if (!partialBlock.IsTxAvailable(i))
- req.indexes.push_back(i);
- }
- if (req.indexes.empty()) {
- // Dirty hack to jump to BLOCKTXN code (TODO: move message handling into their own functions)
- BlockTransactions txn;
- txn.blockhash = cmpctblock.header.GetHash();
- CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
- blockTxnMsg << txn;
- return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams);
- } else {
- req.blockhash = pindex->GetBlockHash();
- pfrom->PushMessage(NetMsgType::GETBLOCKTXN, req);
- }
- }
- } else {
- if (fAlreadyInFlight) {
- // 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, cmpctblock.header.GetHash());
- pfrom->PushMessage(NetMsgType::GETDATA, vInv);
- return true;
- } else {
- // If this was an announce-cmpctblock, we want the same treatment as a header message
- // Dirty hack to process as if it were just a headers message (TODO: move message handling into their own functions)
- std::vector<CBlock> headers;
- headers.push_back(cmpctblock.header);
- CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);
- vHeadersMsg << headers;
- return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams);
- }
- }
-
- CheckBlockIndex(chainparams.GetConsensus());
- }
-
- else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing
- {
- BlockTransactions resp;
- vRecv >> resp;
-
- LOCK(cs_main);
-
- map<uint256, pair<NodeId, 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);
- return true;
- }
-
- PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock;
- CBlock block;
- ReadStatus status = partialBlock.FillBlock(block, resp.txn);
- 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);
- 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, resp.blockhash));
- pfrom->PushMessage(NetMsgType::GETDATA, invs);
- } else {
- CValidationState state;
- ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL);
- int nDoS;
- if (state.IsInvalid(nDoS)) {
- assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
- state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash());
- if (nDoS > 0) {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), nDoS);
- }
- }
- }
- }
-
-
- else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing
- {
- std::vector<CBlockHeader> headers;
-
- // Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
- unsigned int nCount = ReadCompactSize(vRecv);
- if (nCount > MAX_HEADERS_RESULTS) {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 20);
- return error("headers message size = %u", nCount);
- }
- headers.resize(nCount);
- for (unsigned int n = 0; n < nCount; n++) {
- vRecv >> headers[n];
- ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
- }
-
- {
- LOCK(cs_main);
-
- if (nCount == 0) {
- // Nothing interesting. Stop asking this peers for more headers.
- return true;
+ try {
+ uint64_t version;
+ file >> version;
+ if (version != MEMPOOL_DUMP_VERSION) {
+ return false;
}
-
- CNodeState *nodestate = State(pfrom->GetId());
-
- // If this looks like it could be a block announcement (nCount <
- // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
- // don't connect:
- // - Send a getheaders message in response to try to connect the chain.
- // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
- // don't connect before giving DoS points
- // - Once a headers message is received that is valid and does connect,
- // nUnconnectingHeaders gets reset back to 0.
- if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
- nodestate->nUnconnectingHeaders++;
- pfrom->PushMessage(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",
- headers[0].GetHash().ToString(),
- headers[0].hashPrevBlock.ToString(),
- pindexBestHeader->nHeight,
- pfrom->id, 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.
- UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash());
-
- if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
- Misbehaving(pfrom->GetId(), 20);
+ uint64_t num;
+ file >> num;
+ while (num--) {
+ CTransactionRef tx;
+ int64_t nTime;
+ int64_t nFeeDelta;
+ file >> tx;
+ file >> nTime;
+ file >> nFeeDelta;
+
+ CAmount amountdelta = nFeeDelta;
+ if (amountdelta) {
+ mempool.PrioritiseTransaction(tx->GetHash(), amountdelta);
}
- return true;
- }
-
- CBlockIndex *pindexLast = NULL;
- BOOST_FOREACH(const CBlockHeader& header, headers) {
CValidationState state;
- if (pindexLast != NULL && header.hashPrevBlock != pindexLast->GetBlockHash()) {
- Misbehaving(pfrom->GetId(), 20);
- return error("non-continuous headers sequence");
- }
- if (!AcceptBlockHeader(header, state, chainparams, &pindexLast)) {
- int nDoS;
- if (state.IsInvalid(nDoS)) {
- if (nDoS > 0)
- Misbehaving(pfrom->GetId(), nDoS);
- return error("invalid header received");
- }
- }
- }
-
- if (nodestate->nUnconnectingHeaders > 0) {
- LogPrint("net", "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->id, nodestate->nUnconnectingHeaders);
- }
- nodestate->nUnconnectingHeaders = 0;
-
- assert(pindexLast);
- UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
-
- if (nCount == MAX_HEADERS_RESULTS) {
- // 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);
- pfrom->PushMessage(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<CBlockIndex *> vToFetch;
- 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) {
- if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
- !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
- (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
- // We don't have this block, and it's not yet in flight.
- vToFetch.push_back(pindexWalk);
- }
- pindexWalk = pindexWalk->pprev;
- }
- // If pindexWalk still isn't on our main chain, we're looking at a
- // very large reorg at a time we think we're close to caught up to
- // 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",
- pindexLast->GetBlockHash().ToString(),
- pindexLast->nHeight);
- } else {
- vector<CInv> vGetData;
- // Download as much as possible, from earliest to latest.
- BOOST_REVERSE_FOREACH(CBlockIndex *pindex, 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());
- 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);
- }
- if (vGetData.size() > 1) {
- LogPrint("net", "Downloading blocks toward %s (%d) via headers direct fetch\n",
- pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
- }
- if (vGetData.size() > 0) {
- if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(nLocalServices & NODE_WITNESS)) {
- // We seem to be rather well-synced, so it appears pfrom was the first to provide us
- // with this block! Let's get them to announce using compact blocks in the future.
- MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom);
- // In any case, we want to download using a compact block, not a regular one
- vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
- }
- pfrom->PushMessage(NetMsgType::GETDATA, vGetData);
- }
- }
- }
-
- CheckBlockIndex(chainparams.GetConsensus());
- }
-
- NotifyHeaderTip();
- }
-
- else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
- {
- CBlock block;
- vRecv >> block;
-
- LogPrint("net", "received block %s peer=%d\n", block.GetHash().ToString(), pfrom->id);
-
- CValidationState state;
- // Process all blocks from whitelisted peers, even if not requested,
- // unless we're still syncing with the network.
- // Such an unrequested block may still be processed, subject to the
- // conditions in AcceptBlock().
- bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
- ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL);
- int nDoS;
- if (state.IsInvalid(nDoS)) {
- assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
- pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
- state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash());
- if (nDoS > 0) {
+ if (nTime + nExpiryTimeout > nNow) {
LOCK(cs_main);
- Misbehaving(pfrom->GetId(), nDoS);
- }
- }
-
- }
-
-
- else if (strCommand == NetMsgType::GETADDR)
- {
- // This asymmetric behavior for inbound and outbound connections was introduced
- // to prevent a fingerprinting attack: an attacker can send specific fake addresses
- // to users' AddrMan and later request them by sending getaddr messages.
- // 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);
- 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);
- return true;
- }
- pfrom->fSentAddr = true;
-
- pfrom->vAddrToSend.clear();
- vector<CAddress> vAddr = addrman.GetAddr();
- BOOST_FOREACH(const CAddress &addr, vAddr)
- pfrom->PushAddress(addr);
- }
-
-
- else if (strCommand == NetMsgType::MEMPOOL)
- {
- if (!(nLocalServices & NODE_BLOOM) && !pfrom->fWhitelisted)
- {
- LogPrint("net", "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
- pfrom->fDisconnect = true;
- return true;
- }
-
- if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted)
- {
- LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
- pfrom->fDisconnect = true;
- return true;
- }
-
- LOCK(pfrom->cs_inventory);
- pfrom->fSendMempool = true;
- }
-
-
- else if (strCommand == NetMsgType::PING)
- {
- if (pfrom->nVersion > BIP0031_VERSION)
- {
- uint64_t nonce = 0;
- vRecv >> nonce;
- // Echo the message back with the nonce. This allows for two useful features:
- //
- // 1) A remote node can quickly check if the connection is operational
- // 2) Remote nodes can measure the latency of the network thread. If this node
- // is overloaded it won't respond to pings quickly and the remote node can
- // avoid sending us more work, like chain download requests.
- //
- // The nonce stops the remote getting confused between different pings: without
- // 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.
- pfrom->PushMessage(NetMsgType::PONG, nonce);
- }
- }
-
-
- else if (strCommand == NetMsgType::PONG)
- {
- int64_t pingUsecEnd = nTimeReceived;
- uint64_t nonce = 0;
- size_t nAvail = vRecv.in_avail();
- bool bPingFinished = false;
- std::string sProblem;
-
- if (nAvail >= sizeof(nonce)) {
- vRecv >> nonce;
-
- // Only process pong message if there is an outstanding ping (old ping without nonce should never pong)
- if (pfrom->nPingNonceSent != 0) {
- if (nonce == pfrom->nPingNonceSent) {
- // Matching pong received, this ping is no longer outstanding
- bPingFinished = true;
- int64_t pingUsecTime = pingUsecEnd - pfrom->nPingUsecStart;
- if (pingUsecTime > 0) {
- // Successful ping time measurement, replace previous
- pfrom->nPingUsecTime = pingUsecTime;
- pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime);
- } else {
- // This should never happen
- sProblem = "Timing mishap";
- }
+ AcceptToMemoryPoolWithTime(mempool, state, tx, true, NULL, nTime);
+ if (state.IsValid()) {
+ ++count;
} else {
- // Nonce mismatches are normal when pings are overlapping
- sProblem = "Nonce mismatch";
- if (nonce == 0) {
- // This is most likely a bug in another implementation somewhere; cancel this ping
- bPingFinished = true;
- sProblem = "Nonce zero";
- }
+ ++failed;
}
} else {
- sProblem = "Unsolicited pong without ping";
- }
- } else {
- // This is most likely a bug in another implementation somewhere; cancel this ping
- bPingFinished = true;
- sProblem = "Short payload";
- }
-
- if (!(sProblem.empty())) {
- LogPrint("net", "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
- pfrom->id,
- sProblem,
- pfrom->nPingNonceSent,
- nonce,
- nAvail);
- }
- if (bPingFinished) {
- pfrom->nPingNonceSent = 0;
- }
- }
-
-
- else if (strCommand == NetMsgType::FILTERLOAD)
- {
- CBloomFilter filter;
- vRecv >> filter;
-
- LOCK(pfrom->cs_filter);
-
- if (!filter.IsWithinSizeConstraints())
- {
- // There is no excuse for sending a too-large filter
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 100);
- }
- else
- {
- delete pfrom->pfilter;
- pfrom->pfilter = new CBloomFilter(filter);
- pfrom->pfilter->UpdateEmptyFull();
- }
- pfrom->fRelayTxes = true;
- }
-
-
- else if (strCommand == NetMsgType::FILTERADD)
- {
- vector<unsigned char> vData;
- vRecv >> vData;
-
- // Nodes must NEVER send a data item > 520 bytes (the max size for a script data object,
- // and thus, the maximum size any matched object can have) in a filteradd message
- if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE)
- {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 100);
- } else {
- LOCK(pfrom->cs_filter);
- if (pfrom->pfilter)
- pfrom->pfilter->insert(vData);
- else
- {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 100);
- }
- }
- }
-
-
- else if (strCommand == NetMsgType::FILTERCLEAR)
- {
- LOCK(pfrom->cs_filter);
- delete pfrom->pfilter;
- pfrom->pfilter = new CBloomFilter();
- 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");
+ ++skipped;
}
+ if (ShutdownRequested())
+ return false;
}
- }
+ std::map<uint256, CAmount> mapDeltas;
+ file >> mapDeltas;
- else if (strCommand == NetMsgType::FEEFILTER) {
- CAmount newFeeFilter = 0;
- vRecv >> newFeeFilter;
- if (MoneyRange(newFeeFilter)) {
- {
- LOCK(pfrom->cs_feeFilter);
- pfrom->minFeeFilter = newFeeFilter;
- }
- LogPrint("net", "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->id);
+ for (const auto& i : mapDeltas) {
+ 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());
+ return false;
}
- else {
- // Ignore unknown commands for extensibility
- LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id);
- }
-
-
-
+ LogPrintf("Imported mempool transactions from disk: %i successes, %i failed, %i expired\n", count, failed, skipped);
return true;
}
-// requires LOCK(cs_vRecvMsg)
-bool ProcessMessages(CNode* pfrom)
-{
- const CChainParams& chainparams = Params();
- //if (fDebug)
- // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size());
-
- //
- // Message format
- // (4) message start
- // (12) command
- // (4) size
- // (4) checksum
- // (x) data
- //
- bool fOk = true;
-
- if (!pfrom->vRecvGetData.empty())
- ProcessGetData(pfrom, chainparams.GetConsensus());
-
- // this maintains the order of responses
- if (!pfrom->vRecvGetData.empty()) return fOk;
-
- std::deque<CNetMessage>::iterator it = pfrom->vRecvMsg.begin();
- while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) {
- // Don't bother if send buffer is too full to respond anyway
- if (pfrom->nSendSize >= SendBufferSize())
- break;
-
- // get next message
- CNetMessage& msg = *it;
-
- //if (fDebug)
- // LogPrintf("%s(message %u msgsz, %u bytes, complete:%s)\n", __func__,
- // msg.hdr.nMessageSize, msg.vRecv.size(),
- // msg.complete() ? "Y" : "N");
-
- // end, if an incomplete message is found
- if (!msg.complete())
- break;
-
- // at this point, any failure means we can delete the current message
- it++;
-
- // Scan for message start
- if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), MESSAGE_START_SIZE) != 0) {
- LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id);
- fOk = false;
- break;
- }
-
- // 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);
- continue;
- }
- string strCommand = hdr.GetCommand();
-
- // Message size
- unsigned int nMessageSize = hdr.nMessageSize;
-
- // Checksum
- CDataStream& vRecv = msg.vRecv;
- uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
- unsigned int nChecksum = ReadLE32((unsigned char*)&hash);
- if (nChecksum != hdr.nChecksum)
- {
- LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", __func__,
- SanitizeString(strCommand), nMessageSize, nChecksum, hdr.nChecksum);
- continue;
- }
-
- // Process message
- bool fRet = false;
- try
- {
- fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams);
- boost::this_thread::interruption_point();
- }
- catch (const std::ios_base::failure& e)
- {
- pfrom->PushMessage(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()");
- }
- }
- catch (const boost::thread_interrupted&) {
- throw;
- }
- catch (const std::exception& e) {
- PrintExceptionContinue(&e, "ProcessMessages()");
- } catch (...) {
- PrintExceptionContinue(NULL, "ProcessMessages()");
- }
-
- if (!fRet)
- LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id);
-
- break;
- }
-
- // In case the connection got shut down, its receive buffer was wiped
- if (!pfrom->fDisconnect)
- pfrom->vRecvMsg.erase(pfrom->vRecvMsg.begin(), it);
-
- return fOk;
-}
-
-class CompareInvMempoolOrder
+void DumpMempool(void)
{
- CTxMemPool *mp;
-public:
- CompareInvMempoolOrder(CTxMemPool *mempool)
- {
- mp = mempool;
- }
+ int64_t start = GetTimeMicros();
- bool operator()(std::set<uint256>::iterator a, std::set<uint256>::iterator b)
- {
- /* As std::make_heap produces a max-heap, we want the entries with the
- * fewest ancestors/highest fee to sort later. */
- return mp->CompareDepthAndScore(*b, *a);
- }
-};
+ std::map<uint256, CAmount> mapDeltas;
+ std::vector<TxMempoolInfo> vinfo;
-bool SendMessages(CNode* pto)
-{
- const Consensus::Params& consensusParams = Params().GetConsensus();
{
- // Don't send anything until we get its version message
- if (pto->nVersion == 0)
- return true;
-
- //
- // Message: ping
- //
- bool pingSend = false;
- if (pto->fPingQueued) {
- // RPC ping request by user
- pingSend = true;
- }
- if (pto->nPingNonceSent == 0 && pto->nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros()) {
- // Ping automatically sent as a latency probe & keepalive.
- pingSend = true;
- }
- if (pingSend) {
- uint64_t nonce = 0;
- while (nonce == 0) {
- GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
- }
- pto->fPingQueued = false;
- pto->nPingUsecStart = GetTimeMicros();
- if (pto->nVersion > BIP0031_VERSION) {
- pto->nPingNonceSent = nonce;
- pto->PushMessage(NetMsgType::PING, nonce);
- } else {
- // Peer is too old to support ping command with nonce, pong will never arrive.
- pto->nPingNonceSent = 0;
- pto->PushMessage(NetMsgType::PING);
- }
- }
-
- TRY_LOCK(cs_main, lockMain); // Acquire cs_main for IsInitialBlockDownload() and CNodeState()
- if (!lockMain)
- return true;
-
- // Address refresh broadcast
- int64_t nNow = GetTimeMicros();
- if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
- AdvertiseLocal(pto);
- pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
- }
-
- //
- // Message: addr
- //
- if (pto->nNextAddrSend < nNow) {
- pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL);
- vector<CAddress> vAddr;
- vAddr.reserve(pto->vAddrToSend.size());
- BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend)
- {
- if (!pto->addrKnown.contains(addr.GetKey()))
- {
- pto->addrKnown.insert(addr.GetKey());
- vAddr.push_back(addr);
- // receiver rejects addr messages larger than 1000
- if (vAddr.size() >= 1000)
- {
- pto->PushMessage(NetMsgType::ADDR, vAddr);
- vAddr.clear();
- }
- }
- }
- pto->vAddrToSend.clear();
- if (!vAddr.empty())
- pto->PushMessage(NetMsgType::ADDR, vAddr);
- // we only send the big addr message once
- if (pto->vAddrToSend.capacity() > 40)
- pto->vAddrToSend.shrink_to_fit();
+ LOCK(mempool.cs);
+ for (const auto &i : mempool.mapDeltas) {
+ mapDeltas[i.first] = i.second;
}
+ vinfo = mempool.infoAll();
+ }
- CNodeState &state = *State(pto->GetId());
- if (state.fShouldBan) {
- if (pto->fWhitelisted)
- LogPrintf("Warning: not punishing whitelisted 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
- {
- CNode::Ban(pto->addr, BanReasonNodeMisbehaving);
- }
- }
- state.fShouldBan = false;
- }
+ int64_t mid = GetTimeMicros();
- BOOST_FOREACH(const CBlockReject& reject, state.rejects)
- pto->PushMessage(NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock);
- state.rejects.clear();
-
- // Start block sync
- if (pindexBestHeader == NULL)
- 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;
- nSyncStarted++;
- const CBlockIndex *pindexStart = pindexBestHeader;
- /* If possible, start at the block preceding the currently
- best known header. This ensures that we always get a
- non-empty list of headers back as long as the peer
- is up-to-date. With a non-empty response, we can initialise
- the peer's known best block. This wouldn't be possible
- if we requested starting at pindexBestHeader and
- 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);
- pto->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256());
- }
+ try {
+ FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat.new", "wb");
+ if (!filestr) {
+ return;
}
- // Resend wallet transactions that haven't gotten in a block yet
- // Except during reindex, importing and IBD, when old wallet
- // transactions become unconfirmed and spams other nodes.
- if (!fReindex && !fImporting && !IsInitialBlockDownload())
- {
- GetMainSignals().Broadcast(nTimeBestReceived);
- }
+ CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
- //
- // Try sending block announcements via headers
- //
- {
- // If we have less than MAX_BLOCKS_TO_ANNOUNCE in our
- // list of block hashes we're relaying, and our peer wants
- // headers announcements, then find the first header
- // not yet known to our peer but would connect, and send.
- // If no header would connect, or if we have too many
- // blocks, or if the peer doesn't want headers, just
- // add all to the inv queue.
- LOCK(pto->cs_inventory);
- vector<CBlock> vHeaders;
- bool fRevertToInv = ((!state.fPreferHeaders &&
- (!state.fPreferHeaderAndIDs || pto->vBlockHashesToAnnounce.size() > 1)) ||
- pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE);
- CBlockIndex *pBestIndex = NULL; // last header queued for delivery
- ProcessBlockAvailability(pto->id); // 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) {
- BlockMap::iterator mi = mapBlockIndex.find(hash);
- assert(mi != mapBlockIndex.end());
- CBlockIndex *pindex = mi->second;
- if (chainActive[pindex->nHeight] != pindex) {
- // Bail out if we reorged away from this block
- fRevertToInv = true;
- break;
- }
- if (pBestIndex != NULL && 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
- // regular operation (because reorgs should take us to
- // a chain that has some block not on the prior chain,
- // which should be caught by the prior check), but one
- // way this could happen is by using invalidateblock /
- // reconsiderblock repeatedly on the tip, causing it to
- // be added multiple times to vBlockHashesToAnnounce.
- // Robustly deal with this rare situation by reverting
- // to an inv.
- fRevertToInv = true;
- break;
- }
- pBestIndex = pindex;
- if (fFoundStartingHeader) {
- // add this to the headers message
- 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)) {
- // Peer doesn't have this header but they do have the prior one.
- // Start sending headers.
- fFoundStartingHeader = true;
- vHeaders.push_back(pindex->GetBlockHeader());
- } else {
- // Peer doesn't have this header or the prior one -- nothing will
- // connect, so bail out.
- fRevertToInv = true;
- break;
- }
- }
- }
- if (!fRevertToInv && !vHeaders.empty()) {
- 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);
- //TODO: Shouldn't need to reload block from disk, but requires refactor
- CBlock block;
- assert(ReadBlockFromDisk(block, pBestIndex, consensusParams));
- CBlockHeaderAndShortTxIDs cmpctblock(block);
- pto->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, 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__,
- vHeaders.size(),
- vHeaders.front().GetHash().ToString(),
- vHeaders.back().GetHash().ToString(), pto->id);
- } else {
- LogPrint("net", "%s: sending header %s to peer=%d\n", __func__,
- vHeaders.front().GetHash().ToString(), pto->id);
- }
- pto->PushMessage(NetMsgType::HEADERS, vHeaders);
- state.pindexBestHeaderSent = pBestIndex;
- } else
- fRevertToInv = true;
- }
- if (fRevertToInv) {
- // If falling back to using an inv, just try to inv the tip.
- // The last entry in vBlockHashesToAnnounce was our tip at some point
- // in the past.
- if (!pto->vBlockHashesToAnnounce.empty()) {
- const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back();
- BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce);
- assert(mi != mapBlockIndex.end());
- CBlockIndex *pindex = mi->second;
-
- // Warn if we're announcing a block that is not on the main chain.
- // 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",
- hashToAnnounce.ToString(), chainActive.Tip()->GetBlockHash().ToString());
- }
+ uint64_t version = MEMPOOL_DUMP_VERSION;
+ file << version;
- // 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());
- }
- }
- }
- pto->vBlockHashesToAnnounce.clear();
+ file << (uint64_t)vinfo.size();
+ for (const auto& i : vinfo) {
+ file << *(i.tx);
+ file << (int64_t)i.nTime;
+ file << (int64_t)i.nFeeDelta;
+ mapDeltas.erase(i.tx->GetHash());
}
- //
- // Message: inventory
- //
- 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) {
- vInv.push_back(CInv(MSG_BLOCK, hash));
- if (vInv.size() == MAX_INV_SZ) {
- pto->PushMessage(NetMsgType::INV, vInv);
- vInv.clear();
- }
- }
- pto->vInventoryBlockToSend.clear();
-
- // Check whether periodic sends should happen
- bool fSendTrickle = pto->fWhitelisted;
- if (pto->nNextInvSend < nNow) {
- fSendTrickle = true;
- // Use half the delay for outbound peers, as there is less privacy concern for them.
- pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound);
- }
-
- // Time to send but the peer has requested we not relay transactions.
- if (fSendTrickle) {
- LOCK(pto->cs_filter);
- if (!pto->fRelayTxes) pto->setInventoryTxToSend.clear();
- }
-
- // Respond to BIP35 mempool requests
- if (fSendTrickle && pto->fSendMempool) {
- auto vtxinfo = mempool.infoAll();
- pto->fSendMempool = false;
- CAmount filterrate = 0;
- {
- LOCK(pto->cs_feeFilter);
- filterrate = pto->minFeeFilter;
- }
-
- LOCK(pto->cs_filter);
-
- for (const auto& txinfo : vtxinfo) {
- const uint256& hash = txinfo.tx->GetHash();
- CInv inv(MSG_TX, hash);
- pto->setInventoryTxToSend.erase(hash);
- if (filterrate) {
- if (txinfo.feeRate.GetFeePerK() < filterrate)
- continue;
- }
- if (pto->pfilter) {
- if (!pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
- }
- pto->filterInventoryKnown.insert(hash);
- vInv.push_back(inv);
- if (vInv.size() == MAX_INV_SZ) {
- pto->PushMessage(NetMsgType::INV, vInv);
- vInv.clear();
- }
- }
- pto->timeLastMempoolReq = GetTime();
- }
-
- // Determine transactions to relay
- if (fSendTrickle) {
- // Produce a vector with all candidates for sending
- 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);
- }
- CAmount filterrate = 0;
- {
- LOCK(pto->cs_feeFilter);
- filterrate = pto->minFeeFilter;
- }
- // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
- // A heap is used so that not all items need sorting if only a few are being sent.
- CompareInvMempoolOrder compareInvMempoolOrder(&mempool);
- std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
- // No reason to drain out at many times the network's capacity,
- // especially since we have many peers and some will draw much shorter delays.
- unsigned int nRelayedTransactions = 0;
- LOCK(pto->cs_filter);
- while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
- // Fetch the top element from the heap
- std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
- std::set<uint256>::iterator it = vInvTx.back();
- vInvTx.pop_back();
- uint256 hash = *it;
- // Remove it from the to-be-sent set
- pto->setInventoryTxToSend.erase(it);
- // Check if not in the filter already
- if (pto->filterInventoryKnown.contains(hash)) {
- continue;
- }
- // Not in the mempool anymore? don't bother sending it.
- auto txinfo = mempool.info(hash);
- if (!txinfo.tx) {
- continue;
- }
- if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) {
- continue;
- }
- if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
- // Send
- vInv.push_back(CInv(MSG_TX, hash));
- nRelayedTransactions++;
- {
- // Expire old relay messages
- while (!vRelayExpiration.empty() && vRelayExpiration.front().first < nNow)
- {
- mapRelay.erase(vRelayExpiration.front().second);
- vRelayExpiration.pop_front();
- }
+ file << mapDeltas;
+ FileCommit(file.Get());
+ 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);
+ } catch (const std::exception& e) {
+ LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
+ }
+}
- auto ret = mapRelay.insert(std::make_pair(hash, std::move(txinfo.tx)));
- if (ret.second) {
- vRelayExpiration.push_back(std::make_pair(nNow + 15 * 60 * 1000000, ret.first));
- }
- }
- if (vInv.size() == MAX_INV_SZ) {
- pto->PushMessage(NetMsgType::INV, vInv);
- vInv.clear();
- }
- pto->filterInventoryKnown.insert(hash);
- }
- }
- }
- if (!vInv.empty())
- pto->PushMessage(NetMsgType::INV, vInv);
-
- // Detect whether we're stalling
- nNow = GetTimeMicros();
- if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) {
- // 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);
- pto->fDisconnect = true;
- }
- // In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval
- // (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout.
- // We compensate for other peers to prevent killing off peers due to our own downstream link
- // being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes
- // to unreasonably increase our timeout.
- if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) {
- 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);
- pto->fDisconnect = 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)
+ return 0.0;
- //
- // Message: getdata (blocks)
- //
- vector<CInv> vGetData;
- if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
- vector<CBlockIndex*> vToDownload;
- NodeId staller = -1;
- FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
- BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
- if (State(pto->GetId())->fHaveWitness || !IsWitnessEnabled(pindex->pprev, consensusParams)) {
- uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
- 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);
- }
- }
- if (state.nBlocksInFlight == 0 && staller != -1) {
- if (State(staller)->nStallingSince == 0) {
- State(staller)->nStallingSince = nNow;
- LogPrint("net", "Stall started peer=%d\n", staller);
- }
- }
- }
+ int64_t nNow = time(NULL);
- //
- // Message: getdata (non-blocks)
- //
- while (!pto->fDisconnect && !pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
- {
- const CInv& inv = (*pto->mapAskFor.begin()).second;
- if (!AlreadyHave(inv))
- {
- if (fDebug)
- LogPrint("net", "Requesting %s peer=%d\n", inv.ToString(), pto->id);
- vGetData.push_back(inv);
- if (vGetData.size() >= 1000)
- {
- pto->PushMessage(NetMsgType::GETDATA, vGetData);
- vGetData.clear();
- }
- } else {
- //If we're not going to ask, don't expect a response.
- pto->setAskFor.erase(inv.hash);
- }
- pto->mapAskFor.erase(pto->mapAskFor.begin());
- }
- if (!vGetData.empty())
- pto->PushMessage(NetMsgType::GETDATA, vGetData);
+ double fTxTotal;
- //
- // 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();
- int64_t timeNow = GetTimeMicros();
- if (timeNow > pto->nextSendTimeFeeFilter) {
- CAmount filterToSend = filterRounder.round(currentFilter);
- if (filterToSend != pto->lastSentFeeFilter) {
- pto->PushMessage(NetMsgType::FEEFILTER, filterToSend);
- pto->lastSentFeeFilter = filterToSend;
- }
- pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
- }
- // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
- // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
- else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter &&
- (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) {
- pto->nextSendTimeFeeFilter = timeNow + (insecure_rand() % MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
- }
- }
+ if (pindex->nChainTx <= data.nTxCount) {
+ fTxTotal = data.nTxCount + (nNow - data.nTime) * data.dTxRate;
+ } else {
+ fTxTotal = pindex->nChainTx + (nNow - pindex->GetBlockTime()) * data.dTxRate;
}
- return true;
-}
- 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));
- }
-
-ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos)
-{
- LOCK(cs_main);
- return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);
+ return pindex->nChainTx / fTxTotal;
}
class CMainCleanup
@@ -6805,9 +4324,5 @@ public:
for (; it1 != mapBlockIndex.end(); it1++)
delete (*it1).second;
mapBlockIndex.clear();
-
- // orphan transactions
- mapOrphanTransactions.clear();
- mapOrphanTransactionsByPrev.clear();
}
} instance_of_cmaincleanup;
diff --git a/src/main.h b/src/validation.h
index 65ae2488f9..8ddceb2306 100644
--- a/src/main.h
+++ b/src/validation.h
@@ -1,19 +1,20 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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_MAIN_H
-#define BITCOIN_MAIN_H
+#ifndef BITCOIN_VALIDATION_H
+#define BITCOIN_VALIDATION_H
#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif
#include "amount.h"
-#include "chain.h"
#include "coins.h"
-#include "net.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"
@@ -27,6 +28,8 @@
#include <utility>
#include <vector>
+#include <atomic>
+
#include <boost/unordered_map.hpp>
class CBlockIndex;
@@ -34,12 +37,15 @@ class CBlockTreeDB;
class CBloomFilter;
class CChainParams;
class CInv;
+class CConnman;
class CScriptCheck;
+class CBlockPolicyEstimator;
class CTxMemPool;
class CValidationInterface;
class CValidationState;
+struct ChainTxData;
-struct CNodeStateStats;
+struct PrecomputedTransactionData;
struct LockPoints;
/** Default for DEFAULT_WHITELISTRELAY. */
@@ -54,12 +60,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 */
@@ -69,7 +69,7 @@ static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25;
/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */
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 = 72;
+static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 336;
/** 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) */
@@ -88,6 +88,11 @@ static const unsigned int BLOCK_STALLING_TIMEOUT = 2;
/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends
* less than this number, we reached its tip. Changing this value is a protocol upgrade. */
static const unsigned int MAX_HEADERS_RESULTS = 2000;
+/** Maximum depth of blocks we're willing to serve as compact blocks to peers
+ * when requested. For older blocks, a regular BLOCK response will be sent. */
+static const int MAX_CMPCTBLOCK_DEPTH = 5;
+/** Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests for. */
+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
@@ -118,18 +123,17 @@ 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 = 15;
-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;
/** Default for -permitbaremultisig */
static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
-static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = false;
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
-
-static const bool DEFAULT_TESTSAFEMODE = false;
+/** 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 */
@@ -143,6 +147,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(); }
@@ -150,22 +157,22 @@ struct BlockHasher
extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
+extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool;
typedef boost::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
extern BlockMap mapBlockIndex;
extern uint64_t nLastBlockTx;
extern uint64_t nLastBlockSize;
-extern uint64_t nLastBlockCost;
+extern uint64_t nLastBlockWeight;
extern const std::string strMessageMagic;
extern CWaitableCriticalSection csBestBlock;
extern CConditionVariable cvBlockChange;
-extern bool fImporting;
+extern std::atomic_bool fImporting;
extern bool fReindex;
extern int nScriptCheckThreads;
extern bool fTxIndex;
extern bool fIsBareMultisigStd;
extern bool fRequireStandard;
-extern unsigned int nBytesPerSigOp;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
extern size_t nCoinCacheUsage;
@@ -177,6 +184,9 @@ extern CAmount maxTxFee;
extern int64_t nMaxTipAge;
extern bool fEnableReplacement;
+/** Block hash whose ancestors we will assume to have valid scripts without checking them. */
+extern uint256 hashAssumeValid;
+
/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
@@ -193,7 +203,7 @@ extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
-static const signed int DEFAULT_CHECKBLOCKS = MIN_BLOCKS_TO_KEEP;
+static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat)
@@ -206,24 +216,39 @@ static const unsigned int DEFAULT_CHECKLEVEL = 3;
// Setting the target to > than 550MB will make it likely we can respect the target.
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
-/** Register with a network node to receive its signals */
-void RegisterNodeSignals(CNodeSignals& nodeSignals);
-/** Unregister a network node */
-void UnregisterNodeSignals(CNodeSignals& nodeSignals);
-
/**
* Process an incoming block. This only returns after the best known valid
* block is made active. Note that it does not, however, guarantee that the
* specific block passed to it has been checked for validity!
+ *
+ * If you want to *possibly* get feedback on whether pblock is valid, you must
+ * install a CValidationInterface (see validationinterface.h) - this will have
+ * its BlockChecked method called whenever *any* block completes validation.
+ *
+ * Note that we guarantee that either the proof-of-work is valid on pblock, or
+ * (and possibly also) BlockChecked will have been called.
*
- * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
- * @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
+ * Call without cs_main held.
+ *
* @param[in] pblock The block we want to process.
* @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers.
- * @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
+ * @param[out] fNewBlock A boolean which is set to indicate if the block was first received via this call
* @return True if state.IsValid()
*/
-bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp);
+bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool* fNewBlock);
+
+/**
+ * Process incoming block headers.
+ *
+ * Call without cs_main held.
+ *
+ * @param[in] block The block headers themselves
+ * @param[out] state This may be set to an Error state if any error occurred processing them
+ * @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);
+
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
@@ -231,23 +256,15 @@ 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 LoadBlockIndex();
+bool LoadBlockIndex(const CChainParams& chainparams);
/** Unload database information */
void UnloadBlockIndex();
-/** Process protocol messages received from a given node */
-bool ProcessMessages(CNode* pfrom);
-/**
- * Send queued protocol messages to be sent to a give node.
- *
- * @param[in] pto The node which we are sending messages to.
- */
-bool SendMessages(CNode* pto);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
@@ -261,11 +278,14 @@ bool IsInitialBlockDownload();
*/
std::string GetWarnings(const std::string& strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
-bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
+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 */
-bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL);
+bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
+/** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
+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
@@ -284,24 +304,34 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
/**
+ * Mark one block file as pruned.
+ */
+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);
-/** Get statistics from node state */
-bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
-/** Increase a node's misbehavior score. */
-void Misbehaving(NodeId nodeid, int howmuch);
/** Flush all state, indexes and buffers to disk. */
void FlushStateToDisk();
/** Prune block files and flush state to disk. */
void PruneAndFlush();
+/** Prune block files up to a given height */
+void PruneBlockFilesManual(int nManualPruneHeight);
+
+/** (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 fLimitFree,
+ bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced = NULL,
+ bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
-/** (try to) add transaction to memory pool **/
-bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
+/** (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, std::list<CTransactionRef>* plTxnReplaced = NULL,
+ bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
@@ -309,14 +339,8 @@ 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);
-struct CNodeStateStats {
- int nMisbehavior;
- int nSyncHeight;
- int nCommonHeight;
- std::vector<int> vHeightInFlight;
-};
-
-
+/** 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
@@ -349,13 +373,26 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
* instead of being performed inline.
*/
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
- unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL);
+ 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 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
@@ -410,12 +447,13 @@ private:
unsigned int nFlags;
bool cacheStore;
ScriptError error;
+ 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) :
+ 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) { }
+ ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()();
@@ -427,6 +465,7 @@ public:
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
std::swap(error, check.error);
+ std::swap(txdata, check.txdata);
}
ScriptError GetScriptError() const { return error; }
@@ -447,20 +486,8 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
/** 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, CBlockIndex* pindexPrev, int64_t nAdjustedTime);
-bool ContextualCheckBlock(const CBlock& block, CValidationState& state, 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);
+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);
/** 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);
@@ -488,6 +515,9 @@ public:
/** Find the last common block between the parameter chain and a locator. */
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator);
+/** Mark a block as precious and reorganize. */
+bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex);
+
/** Mark a block as invalid. */
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex);
@@ -529,4 +559,13 @@ static const unsigned int REJECT_ALREADY_KNOWN = 0x101;
/** Transaction conflicts with a transaction already known */
static const unsigned int REJECT_CONFLICT = 0x102;
-#endif // BITCOIN_MAIN_H
+/** Get block file info entry for one block file */
+CBlockFileInfo* GetBlockFileInfo(size_t n);
+
+/** Dump the mempool to disk. */
+void DumpMempool();
+
+/** Load the mempool from disk. */
+bool LoadMempool();
+
+#endif // BITCOIN_VALIDATION_H
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 8da0c72858..46d7c9b329 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// 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.
@@ -13,41 +13,40 @@ CMainSignals& GetMainSignals()
}
void RegisterValidationInterface(CValidationInterface* pwalletIn) {
- g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
- g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
- g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
+ g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
+ g_signals.TransactionAddedToMempool.connect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
+ g_signals.BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
+ g_signals.BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
- g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
+ g_signals.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));
}
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
- g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
- g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
+ g_signals.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));
+ g_signals.TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
+ g_signals.BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
+ g_signals.BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
+ g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
+ g_signals.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.TransactionAddedToMempool.disconnect_all_slots();
+ g_signals.BlockConnected.disconnect_all_slots();
+ g_signals.BlockDisconnected.disconnect_all_slots();
g_signals.UpdatedBlockTip.disconnect_all_slots();
-}
-
-void SyncWithWallets(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) {
- g_signals.SyncTransaction(tx, pindex, pblock);
+ g_signals.NewPoWValidBlock.disconnect_all_slots();
}
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 01b8e47650..460aecf243 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -7,14 +7,16 @@
#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;
@@ -27,20 +29,19 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn);
void UnregisterValidationInterface(CValidationInterface* pwalletIn);
/** Unregister all wallets from core */
void UnregisterAllValidationInterfaces();
-/** Push an updated transaction to all registered wallets */
-void SyncWithWallets(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock = NULL);
class CValidationInterface {
protected:
- virtual void UpdatedBlockTip(const CBlockIndex *pindex) {}
- virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) {}
+ virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {}
+ virtual void TransactionAddedToMempool(const CTransactionRef &ptxn) {}
+ virtual void BlockConnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex, const std::vector<CTransactionRef> &txnConflicted) {}
+ virtual void BlockDisconnected(const std::shared_ptr<const CBlock> &block) {}
virtual void SetBestChain(const CBlockLocator &locator) {}
- virtual void UpdatedTransaction(const uint256 &hash) {}
virtual void Inventory(const uint256 &hash) {}
- virtual void ResendWalletTransactions(int64_t nBestBlockTime) {}
+ virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
- virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
- virtual void ResetRequestCount(const uint256 &hash) {};
+ virtual void GetScriptForMining(std::shared_ptr<CReserveScript>&) {};
+ virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
friend void ::RegisterValidationInterface(CValidationInterface*);
friend void ::UnregisterValidationInterface(CValidationInterface*);
friend void ::UnregisterAllValidationInterfaces();
@@ -48,23 +49,35 @@ protected:
struct CMainSignals {
/** Notifies listeners of updated block chain tip */
- boost::signals2::signal<void (const CBlockIndex *)> UpdatedBlockTip;
- /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */
- boost::signals2::signal<void (const CTransaction &, const CBlockIndex *pindex, const CBlock *)> SyncTransaction;
- /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
- boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
+ boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
+ /** Notifies listeners of a transaction having been added to mempool. */
+ boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
+ /**
+ * Notifies listeners of a block being connected.
+ * Provides a vector of transactions evicted from the mempool as a result.
+ */
+ boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef> &)> BlockConnected;
+ /** Notifies listeners of a block being disconnected */
+ boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
/** 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)> Broadcast;
- /** Notifies listeners of a block validation result */
+ boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
+ /**
+ * 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)
+ */
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;
+ boost::signals2::signal<void (std::shared_ptr<CReserveScript>&)> ScriptForMining;
+ /**
+ * 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;
};
CMainSignals& GetMainSignals();
diff --git a/src/version.h b/src/version.h
index 68ccd6d378..0f69b2f02b 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2014 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -9,7 +9,7 @@
* network protocol versioning
*/
-static const int PROTOCOL_VERSION = 70014;
+static const int PROTOCOL_VERSION = 70015;
//! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
@@ -39,7 +39,10 @@ static const int SENDHEADERS_VERSION = 70012;
//! "feefilter" tells peers to filter invs to you by fee starts with this version
static const int FEEFILTER_VERSION = 70013;
-//! shord-id-based block download starts with this version
+//! short-id-based block download starts with this version
static const int SHORT_IDS_BLOCKS_VERSION = 70014;
+//! not banning for invalid compact blocks starts with this version
+static const int INVALID_CB_NO_BAN_VERSION = 70015;
+
#endif // BITCOIN_VERSION_H
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index bf32ae6627..8a7cce7485 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -17,7 +17,7 @@ const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION
},
{
/*.name =*/ "segwit",
- /*.gbt_force =*/ false,
+ /*.gbt_force =*/ true,
}
};
@@ -105,6 +105,36 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
return state;
}
+int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
+{
+ const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
+
+ // BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
+ if (initialState == THRESHOLD_DEFINED) {
+ return 0;
+ }
+
+ const int nPeriod = Period(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.
+ // To ease understanding of the following height calculation, it helps to remember that
+ // 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.
+ 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) {
+ pindexPrev = previousPeriodParent;
+ previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
+ }
+
+ // Adjust the result because right now we point to the parent block.
+ return pindexPrev->nHeight + 1;
+}
+
namespace
{
/**
@@ -137,6 +167,11 @@ ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::
return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]);
}
+int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)
+{
+ return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, cache.caches[pos]);
+}
+
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
return VersionBitsConditionChecker(pos).Mask(params);
diff --git a/src/versionbits.h b/src/versionbits.h
index ede2dcdda8..7a929266aa 100644
--- a/src/versionbits.h
+++ b/src/versionbits.h
@@ -51,8 +51,9 @@ protected:
virtual int Threshold(const Consensus::Params& params) const =0;
public:
- // Note that the function below takes a pindexPrev as input: they compute information for block B based on its parent.
+ // 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;
};
struct VersionBitsCache
@@ -63,6 +64,7 @@ struct VersionBitsCache
};
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
+int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos);
#endif
diff --git a/src/coincontrol.h b/src/wallet/coincontrol.h
index e33adc4d2b..2aa26fb00a 100644
--- a/src/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -1,11 +1,13 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// 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.
-#ifndef BITCOIN_COINCONTROL_H
-#define BITCOIN_COINCONTROL_H
+#ifndef BITCOIN_WALLET_COINCONTROL_H
+#define BITCOIN_WALLET_COINCONTROL_H
+#include "policy/feerate.h"
#include "primitives/transaction.h"
+#include "wallet/wallet.h"
/** Coin Control Features. */
class CCoinControl
@@ -22,6 +24,10 @@ public:
bool fOverrideFeeRate;
//! Feerate to use if overrideFeeRate is true
CFeeRate nFeeRate;
+ //! Override the default confirmation target, 0 = use default
+ int nConfirmTarget;
+ //! Signal BIP-125 replace by fee.
+ bool signalRbf;
CCoinControl()
{
@@ -37,6 +43,8 @@ public:
nMinimumTotalFee = 0;
nFeeRate = CFeeRate(0);
fOverrideFeeRate = false;
+ nConfirmTarget = 0;
+ signalRbf = fWalletRbf;
}
bool HasSelected() const
@@ -73,4 +81,4 @@ private:
std::set<COutPoint> setSelected;
};
-#endif // BITCOIN_COINCONTROL_H
+#endif // BITCOIN_WALLET_COINCONTROL_H
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index 190f8ecf2a..fc318c1612 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -48,12 +48,12 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v
int i = 0;
if (nDerivationMethod == 0)
- i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, chKey, chIV);
+ i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());
if (i != (int)WALLET_CRYPTO_KEY_SIZE)
{
- memory_cleanse(chKey, sizeof(chKey));
- memory_cleanse(chIV, sizeof(chIV));
+ memory_cleanse(vchKey.data(), vchKey.size());
+ memory_cleanse(vchIV.data(), vchIV.size());
return false;
}
@@ -66,8 +66,8 @@ bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigne
if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_SIZE)
return false;
- memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
- memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
+ memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
+ memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());
fKeySet = true;
return true;
@@ -82,7 +82,7 @@ bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned
// n + AES_BLOCKSIZE bytes
vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
- AES256CBCEncrypt enc(chKey, chIV, true);
+ AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), &vchCiphertext[0]);
if(nLen < vchPlaintext.size())
return false;
@@ -101,7 +101,7 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
vchPlaintext.resize(nLen);
- AES256CBCDecrypt dec(chKey, chIV, true);
+ AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
nLen = dec.Decrypt(&vchCiphertext[0], vchCiphertext.size(), &vchPlaintext[0]);
if(nLen == 0)
return false;
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index 5d0a4a3305..275e435f73 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -47,7 +47,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vchCryptedKey);
READWRITE(vchSalt);
READWRITE(nDerivationMethod);
@@ -77,8 +77,8 @@ class CCrypter
{
friend class wallet_crypto::TestCrypter; // for test access to chKey/chIV
private:
- unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
- unsigned char chIV[WALLET_CRYPTO_IV_SIZE];
+ std::vector<unsigned char, secure_allocator<unsigned char>> vchKey;
+ std::vector<unsigned char, secure_allocator<unsigned char>> vchIV;
bool fKeySet;
int BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const;
@@ -91,28 +91,21 @@ public:
void CleanKey()
{
- memory_cleanse(chKey, sizeof(chKey));
- memory_cleanse(chIV, sizeof(chIV));
+ memory_cleanse(vchKey.data(), vchKey.size());
+ memory_cleanse(vchIV.data(), vchIV.size());
fKeySet = false;
}
CCrypter()
{
fKeySet = false;
-
- // Try to keep the key data out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap)
- // Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
- // Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process.
- LockedPageManager::Instance().LockRange(&chKey[0], sizeof chKey);
- LockedPageManager::Instance().LockRange(&chIV[0], sizeof chIV);
+ vchKey.resize(WALLET_CRYPTO_KEY_SIZE);
+ vchIV.resize(WALLET_CRYPTO_IV_SIZE);
}
~CCrypter()
{
CleanKey();
-
- LockedPageManager::Instance().UnlockRange(&chKey[0], sizeof chKey);
- LockedPageManager::Instance().UnlockRange(&chIV[0], sizeof chIV);
}
};
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index c906785e9e..25f6bdd9d9 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -1,11 +1,12 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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 "db.h"
#include "addrman.h"
+#include "fs.h"
#include "hash.h"
#include "protocol.h"
#include "util.h"
@@ -17,16 +18,10 @@
#include <sys/stat.h>
#endif
-#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
#include <boost/thread.hpp>
#include <boost/version.hpp>
-using namespace std;
-
-
-unsigned int nWalletDBUpdated;
-
-
//
// CDB
//
@@ -43,7 +38,7 @@ void CDBEnv::EnvShutdown()
if (ret != 0)
LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb)
- DbEnv(0).remove(strPath.c_str(), 0);
+ DbEnv((u_int32_t)0).remove(strPath.c_str(), 0);
}
void CDBEnv::Reset()
@@ -71,7 +66,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,9 +74,9 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
boost::this_thread::interruption_point();
strPath = pathIn.string();
- boost::filesystem::path pathLogDir = pathIn / "database";
+ fs::path pathLogDir = pathIn / "database";
TryCreateDirectory(pathLogDir);
- boost::filesystem::path pathErrorFile = pathIn / "db.log";
+ fs::path pathErrorFile = pathIn / "db.log";
LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
unsigned int nEnvFlags = 0;
@@ -94,7 +89,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);
@@ -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);
@@ -142,13 +137,13 @@ 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, bool (*recoverFunc)(const std::string& strFile))
{
LOCK(cs_db);
assert(mapFileUseCount.count(strFile) == 0);
@@ -161,10 +156,134 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFu
return RECOVER_FAIL;
// Try to recover:
- bool fRecovered = (*recoverFunc)(*this, strFile);
+ bool fRecovered = (*recoverFunc)(strFile);
return (fRecovered ? RECOVER_OK : RECOVER_FAIL);
}
+bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue))
+{
+ // 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 = bitdb.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;
+ }
+
+ 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(NULL, // 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);
+ return false;
+ }
+
+ DbTxn* ptxn = bitdb.TxnBegin();
+ BOOST_FOREACH(CDBEnv::KeyValPair& row, salvagedData)
+ {
+ if (recoverKVcallback)
+ {
+ CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
+ CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
+ std::string strType, strErr;
+ 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, bool (*recoverFunc)(const std::string& strFile))
+{
+ if (fs::exists(dataDir / walletFile))
+ {
+ CDBEnv::VerifyResult r = bitdb.Verify(walletFile, recoverFunc);
+ 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, "wallet.{timestamp}.bak", 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,7 +298,7 @@ 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);
@@ -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,13 +359,16 @@ 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(NULL), activeTxn(NULL)
{
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;
unsigned int nFlags = DB_THREAD;
@@ -254,22 +376,22 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
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];
+ ++env->mapFileUseCount[strFile];
+ pdb = env->mapDb[strFile];
if (pdb == NULL) {
- pdb = new Db(bitdb.dbenv, 0);
+ 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
@@ -282,19 +404,19 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
if (ret != 0) {
delete pdb;
pdb = NULL;
- --bitdb.mapFileUseCount[strFile];
+ --env->mapFileUseCount[strFile];
strFile = "";
- throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFile));
+ 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,7 @@ 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 ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
}
void CDB::Close()
@@ -325,12 +447,12 @@ void CDB::Close()
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);
@@ -344,32 +466,28 @@ void CDBEnv::CloseDb(const string& strFile)
}
}
-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
strFileRes.c_str(), // Filename
@@ -387,42 +505,42 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
while (fSuccess) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
- if (ret == DB_NOTFOUND) {
+ int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue);
+ if (ret1 == DB_NOTFOUND) {
pcursor->close();
break;
- } else if (ret != 0) {
+ } else if (ret1 != 0) {
pcursor->close();
fSuccess = false;
break;
}
if (pszSkip &&
- strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
+ strncmp(ssKey.data(), pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
continue;
- if (strncmp(&ssKey[0], "\x07version", 8) == 0) {
+ if (strncmp(ssKey.data(), "\x07version", 8) == 0) {
// Update version:
ssValue.clear();
ssValue << CLIENT_VERSION;
}
- Dbt datKey(&ssKey[0], ssKey.size());
- Dbt datValue(&ssValue[0], ssValue.size());
+ Dbt datKey(ssKey.data(), ssKey.size());
+ Dbt datValue(ssValue.data(), ssValue.size());
int ret2 = pdbCopy->put(NULL, &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;
}
}
if (fSuccess) {
- Db dbA(bitdb.dbenv, 0);
+ Db dbA(env->dbenv, 0);
if (dbA.remove(strFile.c_str(), NULL, 0))
fSuccess = false;
- Db dbB(bitdb.dbenv, 0);
+ Db dbB(env->dbenv, 0);
if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
fSuccess = false;
}
@@ -441,38 +559,130 @@ 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);
+ }
+ return false;
+}
+
+void CWalletDBWrapper::Flush(bool shutdown)
+{
+ if (!IsDummy()) {
+ env->Flush(shutdown);
+ }
+}
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 01b8c71a04..3c6870d169 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -7,6 +7,7 @@
#define BITCOIN_WALLET_DB_H
#include "clientversion.h"
+#include "fs.h"
#include "serialize.h"
#include "streams.h"
#include "sync.h"
@@ -16,21 +17,17 @@
#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;
@@ -58,7 +55,7 @@ public:
enum VerifyResult { VERIFY_OK,
RECOVER_OK,
RECOVER_FAIL };
- VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile));
+ VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(const std::string& strFile));
/**
* Salvage data from a file that Verify says is bad.
* fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
@@ -69,13 +66,12 @@ 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)
{
@@ -89,6 +85,52 @@ public:
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(): env(nullptr)
+ {
+ }
+
+ /** Create DB handle to real database */
+ CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in):
+ 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);
+
+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 +141,29 @@ 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:
void Flush();
void Close();
+ static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue));
+
+ /* 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, bool (*recoverFunc)(const std::string& strFile));
private:
CDB(const CDB&);
void operator=(const CDB&);
-protected:
+public:
template <typename K, typename T>
bool Read(const K& key, T& value)
{
@@ -122,35 +174,36 @@ protected:
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
- Dbt datKey(&ssKey[0], ssKey.size());
+ Dbt datKey(ssKey.data(), ssKey.size());
// Read
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() != NULL) {
+ // 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");
@@ -158,20 +211,20 @@ protected:
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
- Dbt datKey(&ssKey[0], ssKey.size());
+ Dbt datKey(ssKey.data(), ssKey.size());
// Value
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
ssValue.reserve(10000);
ssValue << value;
- Dbt datValue(&ssValue[0], ssValue.size());
+ Dbt datValue(ssValue.data(), ssValue.size());
// Write
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);
}
@@ -187,13 +240,13 @@ protected:
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
- Dbt datKey(&ssKey[0], ssKey.size());
+ Dbt datKey(ssKey.data(), ssKey.size());
// Erase
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);
}
@@ -207,13 +260,13 @@ protected:
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
- Dbt datKey(&ssKey[0], ssKey.size());
+ Dbt datKey(ssKey.data(), ssKey.size());
// Exists
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);
}
@@ -228,19 +281,17 @@ protected:
return pcursor;
}
- int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT)
+ int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false)
{
// Read at cursor
Dbt datKey;
- if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
- datKey.set_data(&ssKey[0]);
+ unsigned int fFlags = DB_NEXT;
+ if (setRange) {
+ datKey.set_data(ssKey.data());
datKey.set_size(ssKey.size());
+ fFlags = DB_SET_RANGE;
}
Dbt datValue;
- if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
- datValue.set_data(&ssValue[0]);
- datValue.set_size(ssValue.size());
- }
datKey.set_flags(DB_DBT_MALLOC);
datValue.set_flags(DB_DBT_MALLOC);
int ret = pcursor->get(&datKey, &datValue, fFlags);
@@ -258,8 +309,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;
@@ -306,7 +357,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 = NULL);
};
#endif // BITCOIN_WALLET_DB_H
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
new file mode 100644
index 0000000000..b3cb6a718c
--- /dev/null
+++ b/src/wallet/feebumper.cpp
@@ -0,0 +1,284 @@
+// 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/feebumper.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);
+}
+
+CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConfirmTarget, bool specifiedConfirmTarget, CAmount totalFee, bool newTxReplaceable)
+ :
+ txid(std::move(txidIn)),
+ nOldFee(0),
+ nNewFee(0)
+{
+ vErrors.clear();
+ bumpedTxid.SetNull();
+ AssertLockHeld(pWallet->cs_wallet);
+ if (!pWallet->mapWallet.count(txid)) {
+ vErrors.push_back("Invalid or non-wallet transaction id");
+ currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
+ return;
+ }
+ auto it = pWallet->mapWallet.find(txid);
+ const CWalletTx& wtx = it->second;
+
+ if (pWallet->HasWalletSpend(txid)) {
+ vErrors.push_back("Transaction has descendants in the wallet");
+ currentResult = BumpFeeResult::INVALID_PARAMETER;
+ return;
+ }
+
+ {
+ LOCK(mempool.cs);
+ auto it_mp = mempool.mapTx.find(txid);
+ if (it_mp != mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1) {
+ vErrors.push_back("Transaction has descendants in the mempool");
+ currentResult = BumpFeeResult::INVALID_PARAMETER;
+ return;
+ }
+ }
+
+ if (wtx.GetDepthInMainChain() != 0) {
+ vErrors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
+ currentResult = BumpFeeResult::WALLET_ERROR;
+ 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 = CWallet::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 {
+ // if user specified a confirm target then don't consider any global payTxFee
+ if (specifiedConfirmTarget) {
+ nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, true);
+ }
+ // otherwise use the regular wallet logic to select payTxFee or default confirm target
+ else {
+ nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator);
+ }
+
+ 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(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 (!newTxReplaceable) {
+ 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;
+ }
+ if (txid.IsNull() || !pWallet->mapWallet.count(txid)) {
+ vErrors.push_back("Invalid or non-wallet transaction id");
+ currentResult = BumpFeeResult::MISC_ERROR;
+ return false;
+ }
+ CWalletTx& oldWtx = pWallet->mapWallet[txid];
+
+ 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..681f55e4e5
--- /dev/null
+++ b/src/wallet/feebumper.h
@@ -0,0 +1,56 @@
+// 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 uint256;
+
+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, int newConfirmTarget, bool specifiedConfirmTarget, CAmount totalFee, bool newTxReplaceable);
+ 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:
+ 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/rpcdump.cpp b/src/wallet/rpcdump.cpp
index d55cc68dc0..82708dab26 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -6,7 +6,7 @@
#include "chain.h"
#include "rpc/server.h"
#include "init.h"
-#include "main.h"
+#include "validation.h"
#include "script/script.h"
#include "script/standard.h"
#include "sync.h"
@@ -16,6 +16,8 @@
#include "merkleblock.h"
#include "core_io.h"
+#include "rpcwallet.h"
+
#include <fstream>
#include <stdint.h>
@@ -24,13 +26,9 @@
#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);
}
@@ -74,14 +72,16 @@ std::string DecodeDumpString(const std::string &str) {
return ret.str();
}
-UniValue importprivkey(const UniValue& params, bool fHelp)
+UniValue importprivkey(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
-
- if (fHelp || params.size() < 1 || params.size() > 3)
- throw runtime_error(
- "importprivkey \"bitcoinprivkey\" ( \"label\" rescan )\n"
+ }
+
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
+ throw std::runtime_error(
+ "importprivkey \"bitcoinprivkey\" ( \"label\" ) ( rescan )\n"
"\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
"\nArguments:\n"
"1. \"bitcoinprivkey\" (string, required) The private key (see dumpprivkey)\n"
@@ -95,24 +95,26 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
+ 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 = params[0].get_str();
- string strLabel = "";
- if (params.size() > 1)
- strLabel = params[1].get_str();
+ std::string strSecret = request.params[0].get_str();
+ std::string strLabel = "";
+ if (request.params.size() > 1)
+ strLabel = request.params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
- if (params.size() > 2)
- fRescan = params[2].get_bool();
+ if (request.params.size() > 2)
+ fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
@@ -129,68 +131,100 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
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->ScanForWalletTransactions(chainActive.Genesis(), true);
}
}
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)
{
- if (!isRedeemScript && ::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE)
+ 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", "")
+ );
+
+ if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
+ pwallet->AbortRescan();
+ return true;
+}
+
+void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel);
+void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript)
+{
+ 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, CBitcoinAddress(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 CBitcoinAddress& address, const std::string& strLabel)
{
CScript script = GetScriptForDestination(address.Get());
- ImportScript(script, strLabel, false);
+ ImportScript(pwallet, script, strLabel, false);
// add to address book or update label
if (address.IsValid())
- pwalletMain->SetAddressBook(address.Get(), strLabel, "receive");
+ pwallet->SetAddressBook(address.Get(), strLabel, "receive");
}
-UniValue importaddress(const UniValue& params, bool fHelp)
+UniValue importaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
-
- if (fHelp || params.size() < 1 || params.size() > 4)
- throw runtime_error(
+ }
+
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
+ 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"
@@ -212,78 +246,75 @@ UniValue importaddress(const UniValue& params, bool fHelp)
);
- string strLabel = "";
- if (params.size() > 1)
- strLabel = params[1].get_str();
+ std::string strLabel = "";
+ if (request.params.size() > 1)
+ strLabel = request.params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
- if (params.size() > 2)
- fRescan = params[2].get_bool();
+ if (request.params.size() > 2)
+ fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
// Whether to import a p2sh version, too
bool fP2SH = false;
- if (params.size() > 3)
- fP2SH = params[3].get_bool();
+ if (request.params.size() > 3)
+ fP2SH = request.params[3].get_bool();
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
if (address.IsValid()) {
if (fP2SH)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
- ImportAddress(address, strLabel);
- } else if (IsHex(params[0].get_str())) {
- std::vector<unsigned char> data(ParseHex(params[0].get_str()));
- ImportScript(CScript(data.begin(), data.end()), strLabel, fP2SH);
+ ImportAddress(pwallet, address, strLabel);
+ } else if (IsHex(request.params[0].get_str())) {
+ std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
+ 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->ScanForWalletTransactions(chainActive.Genesis(), true);
+ pwallet->ReacceptWalletTransactions();
}
return NullUniValue;
}
-UniValue importprunedfunds(const UniValue& params, bool fHelp)
+UniValue importprunedfunds(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 2 || params.size() > 3)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 2)
+ 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"
"1. \"rawtransaction\" (string, required) A raw transaction in hex funding an already-existing address in wallet\n"
"2. \"txoutproof\" (string, required) The hex output from gettxoutproof that contains the transaction\n"
- "3. \"label\" (string, optional) An optional label\n"
);
- CTransaction tx;
- if (!DecodeHexTx(tx, params[0].get_str()))
+ CMutableTransaction tx;
+ if (!DecodeHexTx(tx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
uint256 hashTx = tx.GetHash();
- CWalletTx wtx(pwalletMain,tx);
+ CWalletTx wtx(pwallet, MakeTransactionRef(std::move(tx)));
- CDataStream ssMB(ParseHexV(params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
- string strLabel = "";
- if (params.size() == 3)
- strLabel = params[2].get_str();
-
//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) {
@@ -292,7 +323,7 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp)
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");
}
@@ -306,24 +337,25 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp)
wtx.nIndex = txnIndex;
wtx.hashBlock = merkleBlock.header.GetHash();
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- if (pwalletMain->IsMine(tx)) {
- CWalletDB walletdb(pwalletMain->strWalletFile, "r+", false);
- pwalletMain->AddToWallet(wtx, false, &walletdb);
+ if (pwallet->IsMine(wtx)) {
+ pwallet->AddToWallet(wtx, false);
return NullUniValue;
}
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction");
}
-UniValue removeprunedfunds(const UniValue& params, bool fHelp)
+UniValue removeprunedfunds(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1)
+ 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"
"\nArguments:\n"
@@ -334,34 +366,34 @@ UniValue removeprunedfunds(const UniValue& params, bool fHelp)
+ HelpExampleRpc("removprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
- hash.SetHex(params[0].get_str());
- vector<uint256> vHash;
+ hash.SetHex(request.params[0].get_str());
+ 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.");
}
- ThreadFlushWalletDB(pwalletMain->strWalletFile);
-
return NullUniValue;
}
-UniValue importpubkey(const UniValue& params, bool fHelp)
+UniValue importpubkey(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 1 || params.size() > 4)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
+ 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"
@@ -379,47 +411,49 @@ UniValue importpubkey(const UniValue& params, bool fHelp)
);
- string strLabel = "";
- if (params.size() > 1)
- strLabel = params[1].get_str();
+ std::string strLabel = "";
+ if (request.params.size() > 1)
+ strLabel = request.params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
- if (params.size() > 2)
- fRescan = params[2].get_bool();
+ if (request.params.size() > 2)
+ fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
- if (!IsHex(params[0].get_str()))
+ if (!IsHex(request.params[0].get_str()))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
- std::vector<unsigned char> data(ParseHex(params[0].get_str()));
+ std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
CPubKey pubKey(data.begin(), data.end());
if (!pubKey.IsFullyValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- ImportAddress(CBitcoinAddress(pubKey.GetID()), strLabel);
- ImportScript(GetScriptForRawPubKey(pubKey), strLabel, false);
+ ImportAddress(pwallet, CBitcoinAddress(pubKey.GetID()), strLabel);
+ ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);
if (fRescan)
{
- pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
- pwalletMain->ReacceptWalletTransactions();
+ pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);
+ pwallet->ReacceptWalletTransactions();
}
return NullUniValue;
}
-UniValue importwallet(const UniValue& params, bool fHelp)
+UniValue importwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
-
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ }
+
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
"importwallet \"filename\"\n"
"\nImports keys from a wallet dump file (see dumpwallet).\n"
"\nArguments:\n"
@@ -436,12 +470,12 @@ UniValue importwallet(const UniValue& params, bool fHelp)
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;
- file.open(params[0].get_str().c_str(), std::ios::in | std::ios::ate);
+ 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");
@@ -452,9 +486,9 @@ UniValue importwallet(const UniValue& params, bool fHelp)
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] == '#')
@@ -471,7 +505,7 @@ UniValue importwallet(const UniValue& params, bool fHelp)
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
- if (pwalletMain->HaveKey(keyid)) {
+ if (pwallet->HaveKey(keyid)) {
LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString());
continue;
}
@@ -491,28 +525,27 @@ UniValue importwallet(const UniValue& params, bool fHelp)
}
}
LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString());
- if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
+ 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
+ pwallet->ShowProgress("", 100); // hide progress dialog in GUI
CBlockIndex *pindex = chainActive.Tip();
- while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200)
+ while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - TIMESTAMP_WINDOW)
pindex = pindex->pprev;
- if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
- pwalletMain->nTimeFirstKey = nTimeBegin;
+ pwallet->UpdateTimeFirstKey(nTimeBegin);
LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1);
- pwalletMain->ScanForWalletTransactions(pindex);
- pwalletMain->MarkDirty();
+ pwallet->ScanForWalletTransactions(pindex);
+ pwallet->MarkDirty();
if (!fGood)
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
@@ -520,18 +553,20 @@ UniValue importwallet(const UniValue& params, bool fHelp)
return NullUniValue;
}
-UniValue dumpprivkey(const UniValue& params, bool fHelp)
+UniValue dumpprivkey(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
-
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "dumpprivkey \"bitcoinaddress\"\n"
- "\nReveals the private key corresponding to 'bitcoinaddress'.\n"
+ }
+
+ if (request.fHelp || request.params.size() != 1)
+ 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"
"\nArguments:\n"
- "1. \"bitcoinaddress\" (string, required) The bitcoin address for the private key\n"
+ "1. \"address\" (string, required) The bitcoin address for the private key\n"
"\nResult:\n"
"\"key\" (string) The private key\n"
"\nExamples:\n"
@@ -540,11 +575,11 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- EnsureWalletIsUnlocked();
+ EnsureWalletIsUnlocked(pwallet);
- string strAddress = params[0].get_str();
+ std::string strAddress = request.params[0].get_str();
CBitcoinAddress address;
if (!address.SetString(strAddress))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -552,19 +587,22 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
if (!address.GetKeyID(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 UniValue& params, bool fHelp)
+UniValue dumpwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
-
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ }
+
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
"dumpwallet \"filename\"\n"
"\nDumps all wallet keys in a human-readable format.\n"
"\nArguments:\n"
@@ -574,24 +612,26 @@ UniValue dumpwallet(const UniValue& params, bool fHelp)
+ HelpExampleRpc("dumpwallet", "\"test\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- EnsureWalletIsUnlocked();
+ EnsureWalletIsUnlocked(pwallet);
- ofstream file;
- file.open(params[0].get_str().c_str());
+ std::ofstream file;
+ file.open(request.params[0].get_str().c_str());
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
- std::map<CKeyID, int64_t> mapKeyBirth;
+ std::map<CTxDestination, int64_t> mapKeyBirth;
std::set<CKeyID> setKeyPool;
- pwalletMain->GetKeyBirthTimes(mapKeyBirth);
- pwalletMain->GetAllReserveKeys(setKeyPool);
+ pwallet->GetKeyBirthTimes(mapKeyBirth);
+ pwallet->GetAllReserveKeys(setKeyPool);
// 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());
@@ -602,19 +642,41 @@ UniValue dumpwallet(const UniValue& params, bool fHelp)
file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime()));
file << "\n";
+
+ // add the base58check encoded extended master if the wallet uses HD
+ CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID;
+ if (!masterKeyID.IsNull())
+ {
+ CKey key;
+ if (pwallet->GetKey(masterKeyID, key)) {
+ CExtKey masterKey;
+ masterKey.SetMaster(key.begin(), key.size());
+
+ CBitcoinExtKey b58extkey;
+ b58extkey.SetKey(masterKey);
+
+ file << "# extended private masterkey: " << b58extkey.ToString() << "\n\n";
+ }
+ }
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();
CKey key;
- if (pwalletMain->GetKey(keyid, key)) {
- if (pwalletMain->mapAddressBook.count(keyid)) {
- file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr);
+ if (pwallet->GetKey(keyid, key)) {
+ file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime);
+ 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)) {
- file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr);
+ file << "reserve=1";
+ } else if (pwallet->mapKeyMetadata[keyid].hdKeypath == "m") {
+ file << "inactivehdmaster=1";
} else {
- file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr);
+ file << "change=1";
}
+ file << strprintf(" # addr=%s%s\n", strAddr, (pwallet->mapKeyMetadata[keyid].hdKeypath.size() > 0 ? " hdkeypath="+pwallet->mapKeyMetadata[keyid].hdKeypath : ""));
}
}
file << "\n";
@@ -622,3 +684,471 @@ UniValue dumpwallet(const UniValue& params, bool fHelp)
file.close();
return NullUniValue;
}
+
+
+UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp)
+{
+ try {
+ bool success = false;
+
+ // Required fields.
+ const UniValue& scriptPubKey = data["scriptPubKey"];
+
+ // Should have script or JSON with "address".
+ if (!(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address")) && !(scriptPubKey.getType() == UniValue::VSTR)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid scriptPubKey");
+ }
+
+ // Optional fields.
+ 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 std::string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
+
+ bool isScript = scriptPubKey.getType() == UniValue::VSTR;
+ bool isP2SH = strRedeemScript.length() > 0;
+ const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
+
+ // Parse the output.
+ CScript script;
+ CBitcoinAddress address;
+
+ if (!isScript) {
+ address = CBitcoinAddress(output);
+ if (!address.IsValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ }
+ script = GetScriptForDestination(address.Get());
+ } else {
+ if (!IsHex(output)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey");
+ }
+
+ std::vector<unsigned char> vData(ParseHex(output));
+ script = CScript(vData.begin(), vData.end());
+ }
+
+ // Watchonly and private keys
+ if (watchOnly && keys.size()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between watchonly and keys");
+ }
+
+ // Internal + Label
+ if (internal && data.exists("label")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between internal and label");
+ }
+
+ // Not having Internal + Script
+ if (!internal && isScript) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set for hex scriptPubKey");
+ }
+
+ // Keys / PubKeys size check.
+ if (!isP2SH && (keys.size() > 1 || pubKeys.size() > 1)) { // Address / scriptPubKey
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "More than private key given for one address");
+ }
+
+ // Invalid P2SH redeemScript
+ if (isP2SH && !IsHex(strRedeemScript)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script");
+ }
+
+ // Process. //
+
+ // P2SH
+ if (isP2SH) {
+ // Import redeem script.
+ std::vector<unsigned char> vData(ParseHex(strRedeemScript));
+ CScript redeemScript = CScript(vData.begin(), vData.end());
+
+ // Invalid P2SH address
+ if (!script.IsPayToScriptHash()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid P2SH address / script");
+ }
+
+ pwallet->MarkDirty();
+
+ if (!pwallet->AddWatchOnly(redeemScript, timestamp)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ }
+
+ 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());
+
+ if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ }
+
+ pwallet->MarkDirty();
+
+ 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()) {
+ pwallet->SetAddressBook(address.Get(), label, "receive");
+ }
+
+ // Import private keys.
+ if (keys.size()) {
+ for (size_t i = 0; i < keys.size(); i++) {
+ const std::string& privkey = keys[i].get_str();
+
+ CBitcoinSecret vchSecret;
+ bool fGood = vchSecret.SetString(privkey);
+
+ if (!fGood) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
+ }
+
+ CKey key = vchSecret.GetKey();
+
+ if (!key.IsValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
+ }
+
+ CPubKey pubkey = key.GetPubKey();
+ assert(key.VerifyPubKey(pubkey));
+
+ CKeyID vchAddress = pubkey.GetID();
+ pwallet->MarkDirty();
+ pwallet->SetAddressBook(vchAddress, label, "receive");
+
+ if (pwallet->HaveKey(vchAddress)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key");
+ }
+
+ pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
+
+ if (!pwallet->AddKeyPubKey(key, pubkey)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
+ }
+
+ pwallet->UpdateTimeFirstKey(timestamp);
+ }
+ }
+
+ success = true;
+ } else {
+ // Import public keys.
+ if (pubKeys.size() && keys.size() == 0) {
+ const std::string& strPubKey = pubKeys[0].get_str();
+
+ if (!IsHex(strPubKey)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
+ }
+
+ std::vector<unsigned char> vData(ParseHex(strPubKey));
+ CPubKey pubKey(vData.begin(), vData.end());
+
+ if (!pubKey.IsFullyValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
+ }
+
+ CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID());
+
+ // Consistency check.
+ if (!isScript && !(pubKeyAddress.Get() == address.Get())) {
+ 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())) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
+ }
+ }
+ }
+
+ CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get());
+
+ if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ }
+
+ pwallet->MarkDirty();
+
+ 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()) {
+ pwallet->SetAddressBook(pubKeyAddress.Get(), label, "receive");
+ }
+
+ // TODO Is this necessary?
+ CScript scriptRawPubKey = GetScriptForRawPubKey(pubKey);
+
+ if (::IsMine(*pwallet, scriptRawPubKey) == ISMINE_SPENDABLE) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ }
+
+ pwallet->MarkDirty();
+
+ if (!pwallet->AddWatchOnly(scriptRawPubKey, timestamp)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ }
+
+ success = true;
+ }
+
+ // Import private keys.
+ if (keys.size()) {
+ const std::string& strPrivkey = keys[0].get_str();
+
+ // Checks.
+ CBitcoinSecret vchSecret;
+ bool fGood = vchSecret.SetString(strPrivkey);
+
+ if (!fGood) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
+ }
+
+ CKey key = vchSecret.GetKey();
+ if (!key.IsValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
+ }
+
+ CPubKey pubKey = key.GetPubKey();
+ assert(key.VerifyPubKey(pubKey));
+
+ CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID());
+
+ // Consistency check.
+ if (!isScript && !(pubKeyAddress.Get() == address.Get())) {
+ 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())) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
+ }
+ }
+ }
+
+ CKeyID vchAddress = pubKey.GetID();
+ pwallet->MarkDirty();
+ pwallet->SetAddressBook(vchAddress, label, "receive");
+
+ if (pwallet->HaveKey(vchAddress)) {
+ return false;
+ }
+
+ pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
+
+ if (!pwallet->AddKeyPubKey(key, pubKey)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
+ }
+
+ pwallet->UpdateTimeFirstKey(timestamp);
+
+ success = true;
+ }
+
+ // Import scriptPubKey only.
+ if (pubKeys.size() == 0 && keys.size() == 0) {
+ if (::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ }
+
+ pwallet->MarkDirty();
+
+ 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()) {
+ pwallet->SetAddressBook(address.Get(), label, "receive");
+ }
+ }
+
+ success = true;
+ }
+ }
+
+ UniValue result = UniValue(UniValue::VOBJ);
+ result.pushKV("success", UniValue(success));
+ return result;
+ } catch (const UniValue& e) {
+ UniValue result = UniValue(UniValue::VOBJ);
+ result.pushKV("success", UniValue(false));
+ result.pushKV("error", e);
+ return result;
+ } catch (...) {
+ UniValue result = UniValue(UniValue::VOBJ);
+ result.pushKV("success", UniValue(false));
+ result.pushKV("error", JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
+ return result;
+ }
+}
+
+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 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"
+ " \"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"
+ " }\n"
+ " ,...\n"
+ " ]\n"
+ "2. options (json, optional)\n"
+ " {\n"
+ " \"rescan\": <false>, (boolean, optional, default: true) Stating if should rescan the blockchain after all imports\n"
+ " }\n"
+ "\nExamples:\n" +
+ HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, "
+ "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
+ HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'") +
+
+ "\nResponse is an array with the same size as the input that has the execution result :\n"
+ " [{ \"success\": true } , { \"success\": false, \"error\": { \"code\": -1, \"message\": \"Internal Server Error\"} }, ... ]\n");
+
+ // clang-format on
+
+ RPCTypeCheck(mainRequest.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ));
+
+ const UniValue& requests = mainRequest.params[0];
+
+ //Default options
+ bool fRescan = true;
+
+ if (mainRequest.params.size() > 1) {
+ const UniValue& options = mainRequest.params[1];
+
+ if (options.exists("rescan")) {
+ fRescan = options["rescan"].get_bool();
+ }
+ }
+
+ 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;
+ int64_t nLowestTimestamp = 0;
+
+ if (fRescan && chainActive.Tip()) {
+ nLowestTimestamp = chainActive.Tip()->GetBlockTime();
+ } else {
+ fRescan = false;
+ }
+
+ UniValue response(UniValue::VARR);
+
+ BOOST_FOREACH (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) {
+ continue;
+ }
+
+ // If at least one request was successful then allow rescan.
+ if (result["success"].get_bool()) {
+ fRunScan = true;
+ }
+
+ // Get the lowest timestamp.
+ if (timestamp < nLowestTimestamp) {
+ nLowestTimestamp = timestamp;
+ }
+ }
+
+ if (fRescan && fRunScan && requests.size()) {
+ CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(std::max<int64_t>(nLowestTimestamp - TIMESTAMP_WINDOW, 0)) : chainActive.Genesis();
+ CBlockIndex* scannedRange = nullptr;
+ if (pindex) {
+ scannedRange = pwallet->ScanForWalletTransactions(pindex, true);
+ pwallet->ReacceptWalletTransactions();
+ }
+
+ if (!scannedRange || scannedRange->nHeight > pindex->nHeight) {
+ 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 (GetImportTimestamp(request, now) - TIMESTAMP_WINDOW >= scannedRange->GetBlockTimeMax() || 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("Failed to rescan before time %d, transactions may be missing.", scannedRange->GetBlockTimeMax())));
+ response.push_back(std::move(result));
+ }
+ ++i;
+ }
+ }
+ }
+
+ return response;
+}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index b4831ad795..ae4f4f37cb 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1,23 +1,29 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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 "amount.h"
#include "base58.h"
#include "chain.h"
+#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
-#include "main.h"
+#include "wallet/coincontrol.h"
+#include "validation.h"
#include "net.h"
-#include "netbase.h"
+#include "policy/feerate.h"
+#include "policy/fees.h"
+#include "policy/policy.h"
#include "policy/rbf.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/feebumper.h"
+#include "wallet/wallet.h"
+#include "wallet/walletdb.h"
#include <stdint.h>
@@ -25,22 +31,21 @@
#include <univalue.h>
-using namespace std;
-
-int64_t nWalletUnlockTime;
-static CCriticalSection cs_nWalletUnlockTime;
+CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
+{
+ return pwalletMain;
+}
-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 (!pwallet) {
if (!avoidException)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
else
@@ -49,10 +54,11 @@ bool EnsureWalletIsAvailable(bool avoidException)
return true;
}
-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)
@@ -90,25 +96,27 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
}
entry.push_back(Pair("bip125-replaceable", rbfStatus));
- BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
+ BOOST_FOREACH(const PAIRTYPE(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;
}
-UniValue getnewaddress(const UniValue& params, bool fHelp)
+UniValue getnewaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() > 1)
+ 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"
@@ -116,57 +124,61 @@ UniValue getnewaddress(const UniValue& params, bool fHelp)
"\nArguments:\n"
"1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n"
"\nResult:\n"
- "\"bitcoinaddress\" (string) The new bitcoin address\n"
+ "\"address\" (string) The new bitcoin address\n"
"\nExamples:\n"
+ HelpExampleCli("getnewaddress", "")
+ 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 (params.size() > 0)
- strAccount = AccountFromValue(params[0]);
+ std::string strAccount;
+ if (request.params.size() > 0)
+ 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();
}
-CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
+CBitcoinAddress 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());
}
-UniValue getaccountaddress(const UniValue& params, bool fHelp)
+UniValue getaccountaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
"getaccountaddress \"account\"\n"
"\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
"\nArguments:\n"
"1. \"account\" (string, required) The account name for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n"
"\nResult:\n"
- "\"bitcoinaddress\" (string) The account bitcoin address\n"
+ "\"address\" (string) The account bitcoin address\n"
"\nExamples:\n"
+ HelpExampleCli("getaccountaddress", "")
+ HelpExampleCli("getaccountaddress", "\"\"")
@@ -174,25 +186,27 @@ UniValue getaccountaddress(const UniValue& params, bool fHelp)
+ 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(params[0]);
+ std::string strAccount = AccountFromValue(request.params[0]);
UniValue ret(UniValue::VSTR);
- ret = GetAccountAddress(strAccount).ToString();
+ ret = GetAccountAddress(pwallet, strAccount).ToString();
return ret;
}
-UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
+UniValue getrawchangeaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() > 1)
+ 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,14 +217,15 @@ UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
+ 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();
@@ -221,44 +236,45 @@ UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
}
-UniValue setaccount(const UniValue& params, bool fHelp)
+UniValue setaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
- "setaccount \"bitcoinaddress\" \"account\"\n"
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ throw std::runtime_error(
+ "setaccount \"address\" \"account\"\n"
"\nDEPRECATED. Sets the account associated with the given address.\n"
"\nArguments:\n"
- "1. \"bitcoinaddress\" (string, required) The bitcoin address to be associated with an account.\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(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- string strAccount;
- if (params.size() > 1)
- strAccount = AccountFromValue(params[1]);
+ std::string strAccount;
+ if (request.params.size() > 1)
+ strAccount = AccountFromValue(request.params[1]);
// Only add the account if the address is yours.
- if (IsMine(*pwalletMain, address.Get()))
- {
+ if (IsMine(*pwallet, address.Get())) {
// 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(address.Get())) {
+ std::string strOldAccount = pwallet->mapAddressBook[address.Get()].name;
+ if (address == GetAccountAddress(pwallet, strOldAccount)) {
+ GetAccountAddress(pwallet, strOldAccount, true);
+ }
}
- pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
+ pwallet->SetAddressBook(address.Get(), strAccount, "receive");
}
else
throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
@@ -267,52 +283,57 @@ UniValue setaccount(const UniValue& params, bool fHelp)
}
-UniValue getaccount(const UniValue& params, bool fHelp)
+UniValue getaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() != 1)
- throw runtime_error(
- "getaccount \"bitcoinaddress\"\n"
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
+ "getaccount \"address\"\n"
"\nDEPRECATED. Returns the account associated with the given address.\n"
"\nArguments:\n"
- "1. \"bitcoinaddress\" (string, required) The bitcoin address for account lookup.\n"
+ "1. \"address\" (string, required) The bitcoin address for account lookup.\n"
"\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(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
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(address.Get());
+ if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) {
strAccount = (*mi).second.name;
+ }
return strAccount;
}
-UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
+UniValue getaddressesbyaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
"getaddressesbyaccount \"account\"\n"
"\nDEPRECATED. Returns the list of addresses for the given account.\n"
"\nArguments:\n"
- "1. \"account\" (string, required) The account name.\n"
+ "1. \"account\" (string, required) The account name.\n"
"\nResult:\n"
"[ (json array of string)\n"
- " \"bitcoinaddress\" (string) a bitcoin address associated with the given account\n"
+ " \"address\" (string) a bitcoin address associated with the given account\n"
" ,...\n"
"]\n"
"\nExamples:\n"
@@ -320,25 +341,24 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount = AccountFromValue(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)
- {
+ for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) {
const CBitcoinAddress& address = item.first;
- const string& strName = item.second.name;
+ const std::string& strName = item.second.name;
if (strName == strAccount)
ret.push_back(address.ToString());
}
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)
{
- CAmount curBalance = pwalletMain->GetBalance();
+ CAmount curBalance = pwallet->GetBalance();
// Check amount
if (nValue <= 0)
@@ -347,48 +367,57 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
if (nValue > curBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
+ 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 (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
- strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
+ if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
+ 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 (!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);
}
- if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
- throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here.");
}
-UniValue sendtoaddress(const UniValue& params, bool fHelp)
+UniValue sendtoaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 2 || params.size() > 5)
- throw runtime_error(
- "sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
+ throw std::runtime_error(
+ "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount )\n"
"\nSend an amount to a given address.\n"
- + HelpRequiringPassphrase() +
+ + HelpRequiringPassphrase(pwallet) +
"\nArguments:\n"
- "1. \"bitcoinaddress\" (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"
- "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \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"
+ "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
" This is not part of the transaction, just kept in your wallet.\n"
- "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
+ "4. \"comment_to\" (string, optional) A comment to store the name of the person or organization \n"
" to which you're sending the transaction. This is not part of the \n"
" 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"
"\nResult:\n"
- "\"transactionid\" (string) The transaction id.\n"
+ "\"txid\" (string) The transaction id.\n"
"\nExamples:\n"
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
@@ -396,42 +425,44 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
// Amount
- CAmount nAmount = AmountFromValue(params[1]);
+ CAmount nAmount = AmountFromValue(request.params[1]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
// Wallet comments
CWalletTx wtx;
- if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
- wtx.mapValue["comment"] = params[2].get_str();
- if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
- wtx.mapValue["to"] = params[3].get_str();
+ if (request.params.size() > 2 && !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())
+ wtx.mapValue["to"] = request.params[3].get_str();
bool fSubtractFeeFromAmount = false;
- if (params.size() > 4)
- fSubtractFeeFromAmount = params[4].get_bool();
+ if (request.params.size() > 4)
+ fSubtractFeeFromAmount = request.params[4].get_bool();
- EnsureWalletIsUnlocked();
+ EnsureWalletIsUnlocked(pwallet);
- SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
+ SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
return wtx.GetHash().GetHex();
}
-UniValue listaddressgroupings(const UniValue& params, bool fHelp)
+UniValue listaddressgroupings(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp)
- throw runtime_error(
+ if (request.fHelp)
+ 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"
@@ -440,9 +471,9 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
"[\n"
" [\n"
" [\n"
- " \"bitcoinaddress\", (string) The bitcoin address\n"
+ " \"address\", (string) The bitcoin address\n"
" amount, (numeric) The amount in " + CURRENCY_UNIT + "\n"
- " \"account\" (string, optional) The account (DEPRECATED)\n"
+ " \"account\" (string, optional) DEPRECATED. The account\n"
" ]\n"
" ,...\n"
" ]\n"
@@ -453,12 +484,11 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listaddressgroupings", "")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ 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 (std::set<CTxDestination> grouping : pwallet->GetAddressGroupings()) {
UniValue jsonGrouping(UniValue::VARR);
BOOST_FOREACH(CTxDestination address, grouping)
{
@@ -466,8 +496,9 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
addressInfo.push_back(CBitcoinAddress(address).ToString());
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(CBitcoinAddress(address).Get()) != pwallet->mapAddressBook.end()) {
+ addressInfo.push_back(pwallet->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
+ }
}
jsonGrouping.push_back(addressInfo);
}
@@ -476,18 +507,20 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
return jsonGroupings;
}
-UniValue signmessage(const UniValue& params, bool fHelp)
+UniValue signmessage(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() != 2)
- throw runtime_error(
- "signmessage \"bitcoinaddress\" \"message\"\n"
+ if (request.fHelp || request.params.size() != 2)
+ 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. \"bitcoinaddress\" (string, required) The bitcoin address to use for the private key.\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"
"\nResult:\n"
"\"signature\" (string) The signature of the message encoded in base 64\n"
@@ -495,19 +528,19 @@ UniValue signmessage(const UniValue& params, bool fHelp)
"\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 = params[0].get_str();
- string strMessage = 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())
@@ -518,69 +551,72 @@ UniValue signmessage(const UniValue& params, bool fHelp)
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());
}
-UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
+UniValue getreceivedbyaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
- "getreceivedbyaddress \"bitcoinaddress\" ( minconf )\n"
- "\nReturns the total amount received by the given bitcoinaddress in transactions with at least minconf confirmations.\n"
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ 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"
- "1. \"bitcoinaddress\" (string, required) The bitcoin address for transactions.\n"
+ "1. \"address\" (string, required) The bitcoin address for transactions.\n"
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"\nResult:\n"
"amount (numeric) The total amount in " + 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") +
+ + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 0") +
"\nThe amount with at least 6 confirmation, very safe\n"
- + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 6") +
+ + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 6") +
"\nAs a json rpc call\n"
- + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
+ + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
// Bitcoin address
- CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
+ CBitcoinAddress address = CBitcoinAddress(request.params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
CScript scriptPubKey = GetScriptForDestination(address.Get());
- if (!IsMine(*pwalletMain, scriptPubKey))
+ if (!IsMine(*pwallet, scriptPubKey)) {
return ValueFromAmount(0);
+ }
// Minimum confirmations
int nMinDepth = 1;
- if (params.size() > 1)
- nMinDepth = params[1].get_int();
+ if (request.params.size() > 1)
+ 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;
- if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
+ 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.vout)
+ BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
if (txout.scriptPubKey == scriptPubKey)
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
@@ -590,13 +626,15 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
}
-UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
+UniValue getreceivedbyaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ 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,31 +653,31 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
// Minimum confirmations
int nMinDepth = 1;
- if (params.size() > 1)
- nMinDepth = params[1].get_int();
+ if (request.params.size() > 1)
+ nMinDepth = request.params[1].get_int();
// Get the set of pub keys assigned to account
- string strAccount = AccountFromValue(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;
- if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
+ 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.vout)
+ BOOST_FOREACH(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;
+ }
}
}
@@ -647,22 +685,35 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
}
-UniValue getbalance(const UniValue& params, bool fHelp)
+UniValue getbalance(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 3)
- throw runtime_error(
- "getbalance ( \"account\" minconf includeWatchonly )\n"
+ if (request.fHelp || request.params.size() > 3)
+ 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"
- "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\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"
@@ -674,84 +725,59 @@ UniValue getbalance(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getbalance", "\"*\", 6")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
+
+ if (request.params.size() == 0)
+ return ValueFromAmount(pwallet->GetBalance());
- if (params.size() == 0)
- return ValueFromAmount(pwalletMain->GetBalance());
+ const std::string& account_param = request.params[0].get_str();
+ const std::string* account = account_param != "*" ? &account_param : nullptr;
int nMinDepth = 1;
- if (params.size() > 1)
- nMinDepth = params[1].get_int();
+ if (request.params.size() > 1)
+ nMinDepth = request.params[1].get_int();
isminefilter filter = ISMINE_SPENDABLE;
- if(params.size() > 2)
- if(params[2].get_bool())
+ if(request.params.size() > 2)
+ if(request.params[2].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
- if (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;
- }
- return ValueFromAmount(nBalance);
- }
-
- string strAccount = AccountFromValue(params[0]);
-
- CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, filter);
-
- return ValueFromAmount(nBalance);
+ return ValueFromAmount(pwallet->GetLegacyBalance(filter, nMinDepth, account));
}
-UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
+UniValue getunconfirmedbalance(const JSONRPCRequest &request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() > 0)
+ throw std::runtime_error(
"getunconfirmedbalance\n"
"Returns the server's total unconfirmed balance\n");
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
+ return ValueFromAmount(pwallet->GetUnconfirmedBalance());
}
-UniValue movecmd(const UniValue& params, bool fHelp)
+UniValue movecmd(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 3 || params.size() > 5)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 3 || request.params.size() > 5)
+ 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"
"1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n"
"2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n"
"3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n"
- "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
+ "4. (dummy) (numeric, optional) Ignored. Remains for backward compatibility.\n"
"5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
"\nResult:\n"
"true|false (boolean) true if successful.\n"
@@ -764,49 +790,55 @@ UniValue movecmd(const UniValue& params, bool fHelp)
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strFrom = AccountFromValue(params[0]);
- string strTo = AccountFromValue(params[1]);
- CAmount nAmount = AmountFromValue(params[2]);
+ 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 (params.size() > 3)
+ if (request.params.size() > 3)
// unused parameter, used to be nMinDepth, keep type-checking it though
- (void)params[3].get_int();
- string strComment;
- if (params.size() > 4)
- strComment = params[4].get_str();
+ (void)request.params[3].get_int();
+ std::string strComment;
+ if (request.params.size() > 4)
+ 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;
}
-UniValue sendfrom(const UniValue& params, bool fHelp)
+UniValue sendfrom(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 3 || params.size() > 6)
- throw runtime_error(
- "sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
+ if (request.fHelp || request.params.size() < 3 || request.params.size() > 6)
+ 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"
- "2. \"tobitcoinaddress\" (string, required) The bitcoin address to send funds to.\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"
"5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
" This is not part of the transaction, just kept in your wallet.\n"
- "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
+ "6. \"comment_to\" (string, optional) An optional comment to store the name of the person or organization \n"
" to which you're sending the transaction. This is not part of the transaction, \n"
" it is just kept in your wallet.\n"
"\nResult:\n"
- "\"transactionid\" (string) The transaction id.\n"
+ "\"txid\" (string) The transaction id.\n"
"\nExamples:\n"
"\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must have at least 1 confirmation\n"
+ HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
@@ -816,49 +848,51 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
+ HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount = AccountFromValue(params[0]);
- CBitcoinAddress address(params[1].get_str());
+ std::string strAccount = AccountFromValue(request.params[0]);
+ CBitcoinAddress address(request.params[1].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- CAmount nAmount = AmountFromValue(params[2]);
+ CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
int nMinDepth = 1;
- if (params.size() > 3)
- nMinDepth = params[3].get_int();
+ if (request.params.size() > 3)
+ nMinDepth = request.params[3].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
- wtx.mapValue["comment"] = params[4].get_str();
- if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
- wtx.mapValue["to"] = params[5].get_str();
+ if (request.params.size() > 4 && !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())
+ 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);
+ SendMoney(pwallet, address.Get(), nAmount, false, wtx);
return wtx.GetHash().GetHex();
}
-UniValue sendmany(const UniValue& params, bool fHelp)
+UniValue sendmany(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 2 || params.size() > 5)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
+ throw std::runtime_error(
"sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\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"
@@ -868,58 +902,62 @@ UniValue sendmany(const UniValue& params, bool fHelp)
" }\n"
"3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
"4. \"comment\" (string, optional) A comment\n"
- "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
+ "5. subtractfeefrom (array, optional) A json array with addresses.\n"
" The fee will be equally deducted from the amount of each selected address.\n"
" Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
" If no addresses are specified here, the sender pays the fee.\n"
" [\n"
- " \"address\" (string) Subtract fee from this address\n"
+ " \"address\" (string) Subtract fee from this address\n"
" ,...\n"
" ]\n"
"\nResult:\n"
- "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \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);
+ LOCK2(cs_main, pwallet->cs_wallet);
+
+ if (pwallet->GetBroadcastTransactions() && !g_connman) {
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ }
- string strAccount = AccountFromValue(params[0]);
- UniValue sendTo = params[1].get_obj();
+ std::string strAccount = AccountFromValue(request.params[0]);
+ UniValue sendTo = request.params[1].get_obj();
int nMinDepth = 1;
- if (params.size() > 2)
- nMinDepth = params[2].get_int();
+ if (request.params.size() > 2)
+ nMinDepth = request.params[2].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
- wtx.mapValue["comment"] = params[3].get_str();
+ if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ wtx.mapValue["comment"] = request.params[3].get_str();
UniValue subtractFeeFromAmount(UniValue::VARR);
- if (params.size() > 4)
- subtractFeeFromAmount = params[4].get_array();
+ if (request.params.size() > 4)
+ subtractFeeFromAmount = request.params[4].get_array();
- set<CBitcoinAddress> setAddress;
- vector<CRecipient> vecSend;
+ std::set<CBitcoinAddress> setAddress;
+ std::vector<CRecipient> vecSend;
CAmount totalAmount = 0;
- vector<string> keys = sendTo.getKeys();
- BOOST_FOREACH(const string& name_, keys)
+ std::vector<std::string> keys = sendTo.getKeys();
+ BOOST_FOREACH(const std::string& name_, keys)
{
CBitcoinAddress address(name_);
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
+ 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_);
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
setAddress.insert(address);
CScript scriptPubKey = GetScriptForDestination(address.Get());
@@ -939,45 +977,50 @@ UniValue sendmany(const UniValue& params, bool fHelp)
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);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
- if (!pwalletMain->CommitTransaction(wtx, keyChange))
- throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
+ CValidationState state;
+ if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) {
+ strFailReason = strprintf("Transaction commit failed:: %s", state.GetRejectReason());
+ throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
+ }
return wtx.GetHash().GetHex();
}
// 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 UniValue& params, bool fHelp)
+UniValue addmultisigaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 2 || params.size() > 3)
+ 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"
"\nArguments:\n"
"1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
- "2. \"keysobject\" (string, required) A json array of bitcoin addresses or hex-encoded public keys\n"
+ "2. \"keys\" (string, required) A json array of bitcoin addresses or hex-encoded public keys\n"
" [\n"
" \"address\" (string) bitcoin address or hex-encoded public key\n"
" ...,\n"
@@ -985,7 +1028,7 @@ UniValue addmultisigaddress(const UniValue& params, bool fHelp)
"3. \"account\" (string, optional) DEPRECATED. An account to assign the addresses to.\n"
"\nResult:\n"
- "\"bitcoinaddress\" (string) A bitcoin address associated with the keys.\n"
+ "\"address\" (string) A bitcoin address associated with the keys.\n"
"\nExamples:\n"
"\nAdd a multisig address from 2 addresses\n"
@@ -993,38 +1036,44 @@ UniValue addmultisigaddress(const UniValue& params, bool fHelp)
"\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 (params.size() > 2)
- strAccount = AccountFromValue(params[2]);
+ std::string strAccount;
+ if (request.params.size() > 2)
+ strAccount = AccountFromValue(request.params[2]);
// Construct using pay-to-script-hash:
- CScript inner = _createmultisig_redeemScript(params);
+ CScript inner = _createmultisig_redeemScript(pwallet, request.params);
CScriptID innerID(inner);
- pwalletMain->AddCScript(inner);
+ pwallet->AddCScript(inner);
- pwalletMain->SetAddressBook(innerID, strAccount, "send");
+ pwallet->SetAddressBook(innerID, strAccount, "send");
return CBitcoinAddress(innerID).ToString();
}
class Witnessifier : public boost::static_visitor<bool>
{
public:
+ CWallet * const pwallet;
CScriptID result;
+ Witnessifier(CWallet *_pwallet) : pwallet(_pwallet) {}
+
bool operator()(const CNoDestination &dest) const { return false; }
bool operator()(const CKeyID &keyID) {
CPubKey pubkey;
- if (pwalletMain && pwalletMain->GetPubKey(keyID, pubkey)) {
- CScript basescript;
- basescript << ToByteVector(pubkey) << OP_CHECKSIG;
+ if (pwallet) {
+ CScript basescript = GetScriptForDestination(keyID);
+ isminetype typ;
+ typ = IsMine(*pwallet, basescript, SIGVERSION_WITNESS_V0);
+ if (typ != ISMINE_SPENDABLE && typ != ISMINE_WATCH_SOLVABLE)
+ return false;
CScript witscript = GetScriptForWitness(basescript);
- pwalletMain->AddCScript(witscript);
+ pwallet->AddCScript(witscript);
result = CScriptID(witscript);
return true;
}
@@ -1033,15 +1082,19 @@ public:
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;
return true;
}
+ isminetype typ;
+ typ = IsMine(*pwallet, subscript, SIGVERSION_WITNESS_V0);
+ if (typ != ISMINE_SPENDABLE && typ != ISMINE_WATCH_SOLVABLE)
+ return false;
CScript witscript = GetScriptForWitness(subscript);
- pwalletMain->AddCScript(witscript);
+ pwallet->AddCScript(witscript);
result = CScriptID(witscript);
return true;
}
@@ -1049,14 +1102,16 @@ public:
}
};
-UniValue addwitnessaddress(const UniValue& params, bool fHelp)
+UniValue addwitnessaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 1 || params.size() > 1)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
{
- string msg = "addwitnessaddress \"address\"\n"
+ std::string msg = "addwitnessaddress \"address\"\n"
"\nAdd a witness address for a script (with pubkey or redeemscript known).\n"
"It returns the witness script.\n"
@@ -1067,7 +1122,7 @@ UniValue addwitnessaddress(const UniValue& params, bool fHelp)
"\"witnessaddress\", (string) The value of the new address (P2SH of witness script).\n"
"}\n"
;
- throw runtime_error(msg);
+ throw std::runtime_error(msg);
}
{
@@ -1077,17 +1132,19 @@ UniValue addwitnessaddress(const UniValue& params, bool fHelp)
}
}
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- Witnessifier w;
+ Witnessifier w(pwallet);
CTxDestination dest = address.Get();
bool ret = boost::apply_visitor(w, dest);
if (!ret) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet");
+ throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed");
}
+ pwallet->SetAddressBook(w.result, "", "receive");
+
return CBitcoinAddress(w.result).ToString();
}
@@ -1095,7 +1152,7 @@ struct tallyitem
{
CAmount nAmount;
int nConf;
- vector<uint256> txids;
+ std::vector<uint256> txids;
bool fIsWatchonly;
tallyitem()
{
@@ -1105,7 +1162,7 @@ struct tallyitem
}
};
-UniValue ListReceived(const UniValue& params, bool fByAccounts)
+UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByAccounts)
{
// Minimum confirmations
int nMinDepth = 1;
@@ -1123,31 +1180,30 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
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<CBitcoinAddress, tallyitem> mapTally;
+ for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ const CWalletTx& wtx = pairWtx.second;
- if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
+ if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
int nDepth = wtx.GetDepthInMainChain();
if (nDepth < nMinDepth)
continue;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ BOOST_FOREACH(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;
@@ -1156,12 +1212,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)
- {
+ std::map<std::string, tallyitem> mapAccountTally;
+ for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) {
const CBitcoinAddress& address = item.first;
- const string& strAccount = item.second.name;
- map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
+ const std::string& strAccount = item.second.name;
+ std::map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
@@ -1177,10 +1232,10 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
if (fByAccounts)
{
- tallyitem& item = mapAccountTally[strAccount];
- item.nAmount += nAmount;
- item.nConf = min(item.nConf, nConf);
- item.fIsWatchonly = fIsWatchonly;
+ tallyitem& _item = mapAccountTally[strAccount];
+ _item.nAmount += nAmount;
+ _item.nConf = std::min(_item.nConf, nConf);
+ _item.fIsWatchonly = fIsWatchonly;
}
else
{
@@ -1196,9 +1251,9 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
UniValue transactions(UniValue::VARR);
if (it != mapTally.end())
{
- BOOST_FOREACH(const uint256& item, (*it).second.txids)
+ BOOST_FOREACH(const uint256& _item, (*it).second.txids)
{
- transactions.push_back(item.GetHex());
+ transactions.push_back(_item.GetHex());
}
}
obj.push_back(Pair("txids", transactions));
@@ -1208,7 +1263,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;
@@ -1225,19 +1280,21 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
return ret;
}
-UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
+UniValue listreceivedbyaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 3)
- throw runtime_error(
- "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
+ if (request.fHelp || request.params.size() > 3)
+ throw std::runtime_error(
+ "listreceivedbyaddress ( minconf include_empty include_watchonly)\n"
"\nList balances by receiving address.\n"
"\nArguments:\n"
- "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
- "2. includeempty (bool, optional, default=false) Whether to include addresses that haven't received any payments.\n"
- "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
+ "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
+ "2. include_empty (bool, optional, default=false) Whether to include addresses that haven't received any payments.\n"
+ "3. include_watchonly (bool, optional, default=false) Whether to include watch-only addresses (see 'importaddress').\n"
"\nResult:\n"
"[\n"
@@ -1247,7 +1304,11 @@ UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
" \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
" \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
" \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n"
- " \"label\" : \"label\" (string) A comment for the address/transaction, if any\n"
+ " \"label\" : \"label\", (string) A comment for the address/transaction, if any\n"
+ " \"txids\": [\n"
+ " n, (numeric) The ids of transactions received with the address \n"
+ " ...\n"
+ " ]\n"
" }\n"
" ,...\n"
"]\n"
@@ -1258,24 +1319,26 @@ UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- return ListReceived(params, false);
+ return ListReceived(pwallet, request.params, false);
}
-UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
+UniValue listreceivedbyaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 3)
- throw runtime_error(
- "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
+ if (request.fHelp || request.params.size() > 3)
+ throw std::runtime_error(
+ "listreceivedbyaccount ( minconf include_empty include_watchonly)\n"
"\nDEPRECATED. List balances by account.\n"
"\nArguments:\n"
- "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
- "2. includeempty (bool, optional, default=false) Whether to include accounts that haven't received any payments.\n"
- "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
+ "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
+ "2. include_empty (bool, optional, default=false) Whether to include accounts that haven't received any payments.\n"
+ "3. include_watchonly (bool, optional, default=false) Whether to include watch-only addresses (see 'importaddress').\n"
"\nResult:\n"
"[\n"
@@ -1295,9 +1358,9 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listreceivedbyaccount", "6, true, true")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- return ListReceived(params, true);
+ return ListReceived(pwallet, request.params, true);
}
static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
@@ -1307,16 +1370,16 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
entry.push_back(Pair("address", addr.ToString()));
}
-void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
+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
@@ -1325,14 +1388,16 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
BOOST_FOREACH(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)
@@ -1347,14 +1412,16 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
{
BOOST_FOREACH(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())
@@ -1371,8 +1438,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);
@@ -1382,9 +1450,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)
{
@@ -1399,26 +1467,28 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Un
}
}
-UniValue listtransactions(const UniValue& params, bool fHelp)
+UniValue listtransactions(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 4)
- throw runtime_error(
- "listtransactions ( \"account\" count from includeWatchonly)\n"
+ if (request.fHelp || request.params.size() > 4)
+ 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"
"1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
"2. count (numeric, optional, default=10) The number of transactions to return\n"
- "3. from (numeric, optional, default=0) The number of transactions to skip\n"
- "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
+ "3. skip (numeric, optional, default=0) The number of transactions to skip\n"
+ "4. include_watchonly (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\n"
"\nResult:\n"
"[\n"
" {\n"
" \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
" It will be \"\" for the default account.\n"
- " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for \n"
+ " \"address\":\"address\", (string) The bitcoin address of the transaction. Not present for \n"
" move transactions (category = move).\n"
" \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
" transaction between accounts, and not associated with an address,\n"
@@ -1427,14 +1497,14 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
" \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n"
" 'move' category for moves outbound. It is positive for the 'receive' category,\n"
" and for the 'move' category for inbound funds.\n"
+ " \"label\": \"label\", (string) A comment for the address/transaction, if any\n"
" \"vout\": n, (numeric) the vout value\n"
" \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
" 'send' category of transactions.\n"
- " \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable).\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
" 'receive' category of transactions. Negative confirmations indicate the\n"
" transaction conflicts with the block chain\n"
- " \"trusted\": xxx (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.\n"
+ " \"trusted\": xxx, (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.\n"
" \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
" category of transactions.\n"
" \"blockindex\": n, (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive'\n"
@@ -1445,12 +1515,13 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
" \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
" for 'send' and 'receive' category of transactions.\n"
" \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
- " \"label\": \"label\" (string) A comment for the address/transaction, if any\n"
- " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
+ " \"otheraccount\": \"accountname\", (string) DEPRECATED. For the 'move' category of transactions, the account the funds came \n"
" from (for receiving funds, positive amounts), or went to (for sending funds,\n"
" negative amounts).\n"
- " \"bip125-replaceable\": \"yes|no|unknown\" (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
+ " \"bip125-replaceable\": \"yes|no|unknown\", (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
" may be unknown for unconfirmed transactions not in the mempool\n"
+ " \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
+ " 'send' category of transactions.\n"
" }\n"
"]\n"
@@ -1463,20 +1534,20 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount = "*";
- if (params.size() > 0)
- strAccount = params[0].get_str();
+ std::string strAccount = "*";
+ if (request.params.size() > 0)
+ strAccount = request.params[0].get_str();
int nCount = 10;
- if (params.size() > 1)
- nCount = params[1].get_int();
+ if (request.params.size() > 1)
+ nCount = request.params[1].get_int();
int nFrom = 0;
- if (params.size() > 2)
- nFrom = params[2].get_int();
+ if (request.params.size() > 2)
+ nFrom = request.params[2].get_int();
isminefilter filter = ISMINE_SPENDABLE;
- if(params.size() > 3)
- if(params[3].get_bool())
+ if(request.params.size() > 3)
+ if(request.params[3].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
if (nCount < 0)
@@ -1486,14 +1557,14 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
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);
+ ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter);
CAccountingEntry *const pacentry = (*it).second.second;
if (pacentry != 0)
AcentryToJSON(*pacentry, strAccount, ret);
@@ -1507,11 +1578,11 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
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());
@@ -1526,18 +1597,20 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
return ret;
}
-UniValue listaccounts(const UniValue& params, bool fHelp)
+UniValue listaccounts(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 2)
- throw runtime_error(
- "listaccounts ( minconf includeWatchonly)\n"
+ if (request.fHelp || request.params.size() > 2)
+ 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"
- "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
- "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
+ "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
+ "2. include_watchonly (bool, optional, default=false) Include balances in watch-only addresses (see 'importaddress')\n"
"\nResult:\n"
"{ (json object where keys are account names, and values are numeric balances\n"
" \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
@@ -1554,29 +1627,29 @@ UniValue listaccounts(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listaccounts", "6")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
int nMinDepth = 1;
- if (params.size() > 0)
- nMinDepth = params[0].get_int();
+ if (request.params.size() > 0)
+ nMinDepth = request.params[0].get_int();
isminefilter includeWatchonly = ISMINE_SPENDABLE;
- if(params.size() > 1)
- if(params[1].get_bool())
+ if(request.params.size() > 1)
+ 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;
@@ -1587,54 +1660,61 @@ UniValue listaccounts(const UniValue& params, bool fHelp)
if (nDepth >= nMinDepth)
{
BOOST_FOREACH(const COutputEntry& r, listReceived)
- if (pwalletMain->mapAddressBook.count(r.destination))
- mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
+ if (pwallet->mapAddressBook.count(r.destination)) {
+ mapAccountBalances[pwallet->mapAddressBook[r.destination].name] += r.amount;
+ }
else
mapAccountBalances[""] += r.amount;
}
}
- const list<CAccountingEntry> & acentries = pwalletMain->laccentries;
+ const std::list<CAccountingEntry>& acentries = pwallet->laccentries;
BOOST_FOREACH(const CAccountingEntry& entry, acentries)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
UniValue ret(UniValue::VOBJ);
- BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
+ BOOST_FOREACH(const PAIRTYPE(std::string, CAmount)& accountBalance, mapAccountBalances) {
ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
}
return ret;
}
-UniValue listsinceblock(const UniValue& params, bool fHelp)
+UniValue listsinceblock(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp)
- throw runtime_error(
- "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
+ if (request.fHelp)
+ throw std::runtime_error(
+ "listsinceblock ( \"blockhash\" target_confirmations include_watchonly)\n"
"\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\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. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
+ "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')"
"\nResult:\n"
"{\n"
" \"transactions\": [\n"
" \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
- " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
+ " \"address\":\"address\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
" \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
" \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
" outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
" \"vout\" : n, (numeric) the vout value\n"
" \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the 'send' category of transactions.\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
+ " When it's < 0, it means the transaction conflicted that many blocks ago.\n"
" \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
" \"blockindex\": n, (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive' category of transactions.\n"
" \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
" \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
" \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
" \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
+ " \"bip125-replaceable\": \"yes|no|unknown\", (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
+ " may be unknown for unconfirmed transactions not in the mempool\n"
+ " \"abandoned\": xxx, (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the 'send' category of transactions.\n"
" \"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"
@@ -1647,44 +1727,53 @@ UniValue listsinceblock(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- CBlockIndex *pindex = NULL;
+ const CBlockIndex *pindex = NULL;
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
- if (params.size() > 0)
+ if (request.params.size() > 0)
{
uint256 blockId;
- blockId.SetHex(params[0].get_str());
+ blockId.SetHex(request.params[0].get_str());
BlockMap::iterator it = mapBlockIndex.find(blockId);
if (it != mapBlockIndex.end())
+ {
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 (params.size() > 1)
+ if (request.params.size() > 1)
{
- target_confirms = params[1].get_int();
+ target_confirms = request.params[1].get_int();
if (target_confirms < 1)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
}
- if(params.size() > 2)
- if(params[2].get_bool())
- filter = filter | ISMINE_WATCH_ONLY;
+ if (request.params.size() > 2 && request.params[2].get_bool())
+ {
+ filter = filter | ISMINE_WATCH_ONLY;
+ }
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);
+ ListTransactions(pwallet, tx, "*", 0, true, transactions, filter);
}
CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
@@ -1697,21 +1786,25 @@ UniValue listsinceblock(const UniValue& params, bool fHelp)
return ret;
}
-UniValue gettransaction(const UniValue& params, bool fHelp)
+UniValue gettransaction(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
- "gettransaction \"txid\" ( includeWatchonly )\n"
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ throw std::runtime_error(
+ "gettransaction \"txid\" ( include_watchonly )\n"
"\nGet detailed information about in-wallet transaction <txid>\n"
"\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id\n"
- "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
+ "1. \"txid\" (string, required) The transaction id\n"
+ "2. \"include_watchonly\" (bool, optional, default=false) Whether to include watch-only addresses in balance calculation and details[]\n"
"\nResult:\n"
"{\n"
" \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
+ " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
+ " 'send' category of transactions.\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
" \"blockhash\" : \"hash\", (string) The block hash\n"
" \"blockindex\" : xx, (numeric) The index of the transaction in the block that includes it\n"
@@ -1719,16 +1812,20 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
" \"txid\" : \"transactionid\", (string) The transaction id.\n"
" \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
" \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
- " \"bip125-replaceable\": \"yes|no|unknown\" (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
+ " \"bip125-replaceable\": \"yes|no|unknown\", (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
" may be unknown for unconfirmed transactions not in the mempool\n"
" \"details\" : [\n"
" {\n"
- " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
- " \"address\" : \"bitcoinaddress\", (string) The bitcoin address involved in the transaction\n"
+ " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
+ " \"address\" : \"address\", (string) The bitcoin address involved in the transaction\n"
" \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
" \"amount\" : x.xxx, (numeric) The amount in " + CURRENCY_UNIT + "\n"
" \"label\" : \"label\", (string) A comment for the address/transaction, if any\n"
" \"vout\" : n, (numeric) the vout value\n"
+ " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
+ " 'send' category of transactions.\n"
+ " \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
+ " 'send' category of transactions.\n"
" }\n"
" ,...\n"
" ],\n"
@@ -1741,25 +1838,26 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
- hash.SetHex(params[0].get_str());
+ hash.SetHex(request.params[0].get_str());
isminefilter filter = ISMINE_SPENDABLE;
- if(params.size() > 1)
- if(params[1].get_bool())
+ if(request.params.size() > 1)
+ if(request.params[1].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
UniValue entry(UniValue::VOBJ);
- if (!pwalletMain->mapWallet.count(hash))
+ if (!pwallet->mapWallet.count(hash)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
- const CWalletTx& wtx = pwalletMain->mapWallet[hash];
+ }
+ const CWalletTx& wtx = pwallet->mapWallet[hash];
CAmount nCredit = wtx.GetCredit(filter);
CAmount nDebit = wtx.GetDebit(filter);
CAmount nNet = nCredit - nDebit;
- CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
+ CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
if (wtx.IsFromMe(filter))
@@ -1768,22 +1866,24 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
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));
+ std::string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
entry.push_back(Pair("hex", strHex));
return entry;
}
-UniValue abandontransaction(const UniValue& params, bool fHelp)
+UniValue abandontransaction(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1)
+ 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"
@@ -1798,27 +1898,31 @@ UniValue abandontransaction(const UniValue& params, bool fHelp)
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
- hash.SetHex(params[0].get_str());
+ 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;
}
-UniValue backupwallet(const UniValue& params, bool fHelp)
+UniValue backupwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() != 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 1)
+ 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"
@@ -1828,26 +1932,29 @@ UniValue backupwallet(const UniValue& params, bool fHelp)
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strDest = 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;
}
-UniValue keypoolrefill(const UniValue& params, bool fHelp)
+UniValue keypoolrefill(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() > 1)
+ 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"
@@ -1855,21 +1962,22 @@ UniValue keypoolrefill(const UniValue& params, bool fHelp)
+ 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 (params.size() > 0) {
- if (params[0].get_int() < 0)
+ if (request.params.size() > 0) {
+ if (request.params[0].get_int() < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
- kpSize = (unsigned int)params[0].get_int();
+ 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;
}
@@ -1877,18 +1985,20 @@ UniValue keypoolrefill(const UniValue& params, bool fHelp)
static void LockWallet(CWallet* pWallet)
{
- LOCK(cs_nWalletUnlockTime);
- nWalletUnlockTime = 0;
+ LOCK(pWallet->cs_wallet);
+ pWallet->nRelockTime = 0;
pWallet->Lock();
}
-UniValue walletpassphrase(const UniValue& params, bool fHelp)
+UniValue walletpassphrase(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (pwalletMain->IsCrypted() && (fHelp || 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"
@@ -1906,49 +2016,53 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp)
"\nAs json rpc call\n"
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
);
+ }
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- if (fHelp)
+ 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 params[0] which is not mlock()ed
+ // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
SecureString strWalletPass;
strWalletPass.reserve(100);
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make params[0] mlock()'d to begin with.
- strWalletPass = params[0].get_str().c_str();
+ // Alternately, find a way to make request.params[0] mlock()'d to begin with.
+ strWalletPass = request.params[0].get_str().c_str();
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 = params[1].get_int64();
- LOCK(cs_nWalletUnlockTime);
- nWalletUnlockTime = GetTime() + nSleepTime;
- RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
+ int64_t nSleepTime = request.params[1].get_int64();
+ pwallet->nRelockTime = GetTime() + nSleepTime;
+ RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), boost::bind(LockWallet, pwallet), nSleepTime);
return NullUniValue;
}
-UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
+UniValue walletpassphrasechange(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (pwalletMain->IsCrypted() && (fHelp || 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"
@@ -1958,43 +2072,48 @@ UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
+ 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 (fHelp)
+ 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 params[0] mlock()'d to begin with.
+ // Alternately, find a way to make request.params[0] mlock()'d to begin with.
SecureString strOldWalletPass;
strOldWalletPass.reserve(100);
- strOldWalletPass = params[0].get_str().c_str();
+ strOldWalletPass = request.params[0].get_str().c_str();
SecureString strNewWalletPass;
strNewWalletPass.reserve(100);
- strNewWalletPass = params[1].get_str().c_str();
+ 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;
}
-UniValue walletlock(const UniValue& params, bool fHelp)
+UniValue walletlock(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (pwalletMain->IsCrypted() && (fHelp || 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"
@@ -2009,31 +2128,32 @@ UniValue walletlock(const UniValue& params, bool fHelp)
"\nAs json rpc call\n"
+ HelpExampleRpc("walletlock", "")
);
+ }
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- if (fHelp)
+ 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 UniValue& params, bool fHelp)
+UniValue encryptwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (!pwalletMain->IsCrypted() && (fHelp || 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"
@@ -2049,48 +2169,53 @@ UniValue encryptwallet(const UniValue& params, bool fHelp)
"\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"
- + HelpExampleCli("signmessage", "\"bitcoinaddress\" \"test message\"") +
+ + 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 (fHelp)
+ 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 params[0] mlock()'d to begin with.
+ // Alternately, find a way to make request.params[0] mlock()'d to begin with.
SecureString strWalletPass;
strWalletPass.reserve(100);
- strWalletPass = params[0].get_str().c_str();
+ 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
// unencrypted private keys. So:
StartShutdown();
- return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
+ return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup.";
}
-UniValue lockunspent(const UniValue& params, bool fHelp)
+UniValue lockunspent(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ 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"
@@ -2126,22 +2251,22 @@ UniValue lockunspent(const UniValue& params, bool fHelp)
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- if (params.size() == 1)
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
+ if (request.params.size() == 1)
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VBOOL));
else
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
- bool fUnlock = params[0].get_bool();
+ bool fUnlock = request.params[0].get_bool();
- if (params.size() == 1) {
+ if (request.params.size() == 1) {
if (fUnlock)
- pwalletMain->UnlockAllCoins();
+ pwallet->UnlockAllCoins();
return true;
}
- UniValue outputs = params[1].get_array();
+ UniValue outputs = request.params[1].get_array();
for (unsigned int idx = 0; idx < outputs.size(); idx++) {
const UniValue& output = outputs[idx];
if (!output.isObject())
@@ -2154,7 +2279,7 @@ UniValue lockunspent(const UniValue& params, bool fHelp)
{"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");
@@ -2165,21 +2290,23 @@ UniValue lockunspent(const UniValue& params, bool fHelp)
COutPoint outpt(uint256S(txid), nOutput);
if (fUnlock)
- pwalletMain->UnlockCoin(outpt);
+ pwallet->UnlockCoin(outpt);
else
- pwalletMain->LockCoin(outpt);
+ pwallet->LockCoin(outpt);
}
return true;
}
-UniValue listlockunspent(const UniValue& params, bool fHelp)
+UniValue listlockunspent(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() > 0)
+ 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"
@@ -2204,10 +2331,10 @@ UniValue listlockunspent(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listlockunspent", "")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- vector<COutPoint> vOutpts;
- pwalletMain->ListLockedCoins(vOutpts);
+ std::vector<COutPoint> vOutpts;
+ pwallet->ListLockedCoins(vOutpts);
UniValue ret(UniValue::VARR);
@@ -2222,13 +2349,15 @@ UniValue listlockunspent(const UniValue& params, bool fHelp)
return ret;
}
-UniValue settxfee(const UniValue& params, bool fHelp)
+UniValue settxfee(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 1 || params.size() > 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
+ throw std::runtime_error(
"settxfee amount\n"
"\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n"
"\nArguments:\n"
@@ -2240,68 +2369,79 @@ UniValue settxfee(const UniValue& params, bool fHelp)
+ HelpExampleRpc("settxfee", "0.00001")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
// Amount
- CAmount nAmount = AmountFromValue(params[0]);
+ CAmount nAmount = AmountFromValue(request.params[0]);
payTxFee = CFeeRate(nAmount, 1000);
return true;
}
-UniValue getwalletinfo(const UniValue& params, bool fHelp)
+UniValue getwalletinfo(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ 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 GMT epoch) of the oldest pre-generated key in the key pool\n"
- " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
- " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
- " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
- " \"masterkeyid\": \"<hash160>\", (string) the Hash160 of the HD master pubkey\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);
+ 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("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("masterkeyid", masterKeyID.GetHex()));
+ obj.push_back(Pair("hdmasterkeyid", masterKeyID.GetHex()));
return obj;
}
-UniValue resendwallettransactions(const UniValue& params, bool fHelp)
+UniValue resendwallettransactions(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() != 0)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ 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"
@@ -2309,9 +2449,12 @@ UniValue resendwallettransactions(const UniValue& params, bool fHelp)
"Returns array of transaction ids that were re-broadcast.\n"
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ if (!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
+ LOCK2(cs_main, pwallet->cs_wallet);
- std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
+ std::vector<uint256> txids = pwallet->ResendWalletTransactionsBefore(GetTime(), g_connman.get());
UniValue result(UniValue::VARR);
BOOST_FOREACH(const uint256& txid, txids)
{
@@ -2320,25 +2463,36 @@ UniValue resendwallettransactions(const UniValue& params, bool fHelp)
return result;
}
-UniValue listunspent(const UniValue& params, bool fHelp)
+UniValue listunspent(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() > 3)
- throw runtime_error(
- "listunspent ( minconf maxconf [\"address\",...] )\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"
@@ -2347,11 +2501,14 @@ UniValue listunspent(const UniValue& params, bool fHelp)
" \"address\" : \"address\", (string) the bitcoin address\n"
" \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
" \"scriptPubKey\" : \"key\", (string) the script key\n"
- " \"amount\" : x.xxx, (numeric) the transaction amount in " + 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"
@@ -2360,43 +2517,73 @@ UniValue listunspent(const UniValue& params, bool fHelp)
+ 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(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
-
int nMinDepth = 1;
- if (params.size() > 0)
- nMinDepth = params[0].get_int();
+ if (request.params.size() > 0 && !request.params[0].isNull()) {
+ RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
+ nMinDepth = request.params[0].get_int();
+ }
int nMaxDepth = 9999999;
- if (params.size() > 1)
- nMaxDepth = params[1].get_int();
+ if (request.params.size() > 1 && !request.params[1].isNull()) {
+ RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
+ nMaxDepth = request.params[1].get_int();
+ }
- set<CBitcoinAddress> setAddress;
- if (params.size() > 2) {
- UniValue inputs = params[2].get_array();
+ std::set<CBitcoinAddress> setAddress;
+ if (request.params.size() > 2 && !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());
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+input.get_str());
if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+input.get_str());
setAddress.insert(address);
}
}
+ bool include_unsafe = true;
+ if (request.params.size() > 3 && !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.size() > 4) {
+ 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 != NULL);
+ LOCK2(cs_main, pwallet->cs_wallet);
+ pwallet->AvailableCoins(vecOutputs, !include_unsafe, NULL, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
+ BOOST_FOREACH(const COutput& out, vecOutputs) {
CTxDestination address;
- const CScript& scriptPubKey = out.tx->vout[out.i].scriptPubKey;
+ const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
bool fValidAddress = ExtractDestination(scriptPubKey, address);
if (setAddress.size() && (!fValidAddress || !setAddress.count(address)))
@@ -2409,38 +2596,44 @@ UniValue listunspent(const UniValue& params, bool fHelp)
if (fValidAddress) {
entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
- 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())));
+ }
}
}
entry.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
- entry.push_back(Pair("amount", ValueFromAmount(out.tx->vout[out.i].nValue)));
+ entry.push_back(Pair("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue)));
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);
}
return results;
}
-UniValue fundrawtransaction(const UniValue& params, bool fHelp)
+UniValue fundrawtransaction(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (fHelp || params.size() < 1 || params.size() > 2)
- throw runtime_error(
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ 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 one change output to the outputs.\n"
+ "This will not modify existing inputs, and will add at most one change output to the outputs.\n"
+ "No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
"Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
"The inputs added will not be signed, use signrawtransaction for that.\n"
"Note that all existing inputs must have their previous output transaction be in the wallet.\n"
@@ -2450,13 +2643,20 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
"Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n"
"\nArguments:\n"
"1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
- "2. options (object, optional)\n"
+ "2. options (object, optional)\n"
" {\n"
- " \"changeAddress\" (string, optional, default pool address) The bitcoin address to receive the change\n"
- " \"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"
+ " \"changeAddress\" (string, optional, default pool address) The bitcoin address to receive the change\n"
+ " \"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"
+ " \"reserveChangeKey\" (boolean, optional, default true) Reserves the change output key from the keypool\n"
+ " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific feerate (" + CURRENCY_UNIT + " per 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"
" }\n"
" for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n"
"\nResult:\n"
@@ -2465,7 +2665,6 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
" \"fee\": n, (numeric) Fee in " + CURRENCY_UNIT + " the resulting transaction pays\n"
" \"changepos\": n (numeric) The position of the added change output, or -1\n"
"}\n"
- "\"hex\" \n"
"\nExamples:\n"
"\nCreate a transaction with no inputs\n"
+ HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
@@ -2477,24 +2676,27 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
CTxDestination changeAddress = CNoDestination();
int changePosition = -1;
bool includeWatching = false;
bool lockUnspents = false;
+ bool reserveChangeKey = true;
CFeeRate feeRate = CFeeRate(0);
bool overrideEstimatedFeerate = false;
+ UniValue subtractFeeFromOutputs;
+ std::set<int> setSubtractFeeFromOutputs;
- if (params.size() > 1) {
- if (params[1].type() == UniValue::VBOOL) {
+ if (request.params.size() > 1) {
+ if (request.params[1].type() == UniValue::VBOOL) {
// backward compatibility bool only fallback
- includeWatching = params[1].get_bool();
+ includeWatching = request.params[1].get_bool();
}
else {
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VOBJ));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VOBJ));
- UniValue options = params[1];
+ UniValue options = request.params[1];
RPCTypeCheckObj(options,
{
@@ -2502,7 +2704,9 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
{"changePosition", UniValueType(UniValue::VNUM)},
{"includeWatching", UniValueType(UniValue::VBOOL)},
{"lockUnspents", UniValueType(UniValue::VBOOL)},
+ {"reserveChangeKey", UniValueType(UniValue::VBOOL)},
{"feeRate", UniValueType()}, // will be checked below
+ {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
},
true, true);
@@ -2510,7 +2714,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
CBitcoinAddress address(options["changeAddress"].get_str());
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid bitcoin address");
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address");
changeAddress = address.Get();
}
@@ -2524,31 +2728,48 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
if (options.exists("lockUnspents"))
lockUnspents = options["lockUnspents"].get_bool();
+ if (options.exists("reserveChangeKey"))
+ reserveChangeKey = options["reserveChangeKey"].get_bool();
+
if (options.exists("feeRate"))
{
feeRate = CFeeRate(AmountFromValue(options["feeRate"]));
overrideEstimatedFeerate = true;
}
+
+ if (options.exists("subtractFeeFromOutputs"))
+ subtractFeeFromOutputs = options["subtractFeeFromOutputs"].get_array();
}
}
// parse hex string from parameter
- CTransaction origTx;
- if (!DecodeHexTx(origTx, params[0].get_str(), true))
+ CMutableTransaction tx;
+ if (!DecodeHexTx(tx, request.params[0].get_str(), true))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
- if (origTx.vout.size() == 0)
+ if (tx.vout.size() == 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
- if (changePosition != -1 && (changePosition < 0 || (unsigned int)changePosition > origTx.vout.size()))
+ if (changePosition != -1 && (changePosition < 0 || (unsigned int)changePosition > tx.vout.size()))
throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
- CMutableTransaction tx(origTx);
+ for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {
+ int pos = subtractFeeFromOutputs[idx].get_int();
+ if (setSubtractFeeFromOutputs.count(pos))
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos));
+ if (pos < 0)
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, negative position: %d", pos));
+ if (pos >= int(tx.vout.size()))
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, position too large: %d", pos));
+ setSubtractFeeFromOutputs.insert(pos);
+ }
+
CAmount nFeeOut;
- string strFailReason;
+ std::string strFailReason;
- if(!pwalletMain->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, changeAddress))
- throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
+ if (!pwallet->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, setSubtractFeeFromOutputs, reserveChangeKey, changeAddress)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
+ }
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", EncodeHexTx(tx)));
@@ -2558,68 +2779,211 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
return result;
}
-extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
-extern UniValue importprivkey(const UniValue& params, bool fHelp);
-extern UniValue importaddress(const UniValue& params, bool fHelp);
-extern UniValue importpubkey(const UniValue& params, bool fHelp);
-extern UniValue dumpwallet(const UniValue& params, bool fHelp);
-extern UniValue importwallet(const UniValue& params, bool fHelp);
-extern UniValue importprunedfunds(const UniValue& params, bool fHelp);
-extern UniValue removeprunedfunds(const UniValue& params, bool fHelp);
+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"
+ " }\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, boost::assign::list_of(UniValue::VSTR)(UniValue::VOBJ));
+ uint256 hash;
+ hash.SetHex(request.params[0].get_str());
+
+ // optional parameters
+ bool specifiedConfirmTarget = false;
+ int newConfirmTarget = nTxConfirmTarget;
+ CAmount totalFee = 0;
+ bool replaceable = true;
+ if (request.params.size() > 1) {
+ UniValue options = request.params[1];
+ RPCTypeCheckObj(options,
+ {
+ {"confTarget", UniValueType(UniValue::VNUM)},
+ {"totalFee", UniValueType(UniValue::VNUM)},
+ {"replaceable", UniValueType(UniValue::VBOOL)},
+ },
+ 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")) {
+ specifiedConfirmTarget = true;
+ newConfirmTarget = options["confTarget"].get_int();
+ if (newConfirmTarget <= 0) { // upper-bound will be checked by estimatefee/smartfee
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid confTarget (cannot be <= 0)");
+ }
+ } 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")) {
+ replaceable = options["replaceable"].get_bool();
+ }
+ }
+
+ LOCK2(cs_main, pwallet->cs_wallet);
+ EnsureWalletIsUnlocked(pwallet);
+
+ CFeeBumper feeBump(pwallet, hash, newConfirmTarget, specifiedConfirmTarget, totalFee, replaceable);
+ 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(errors);
+
+ return result;
+}
+
+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);
+extern UniValue importpubkey(const JSONRPCRequest& request);
+extern UniValue dumpwallet(const JSONRPCRequest& request);
+extern UniValue importwallet(const JSONRPCRequest& request);
+extern UniValue importprunedfunds(const JSONRPCRequest& request);
+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 },
- { "hidden", "resendwallettransactions", &resendwallettransactions, true },
- { "wallet", "abandontransaction", &abandontransaction, false },
- { "wallet", "addmultisigaddress", &addmultisigaddress, true },
- { "wallet", "addwitnessaddress", &addwitnessaddress, true },
- { "wallet", "backupwallet", &backupwallet, true },
- { "wallet", "dumpprivkey", &dumpprivkey, true },
- { "wallet", "dumpwallet", &dumpwallet, true },
- { "wallet", "encryptwallet", &encryptwallet, true },
- { "wallet", "getaccountaddress", &getaccountaddress, true },
- { "wallet", "getaccount", &getaccount, true },
- { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true },
- { "wallet", "getbalance", &getbalance, false },
- { "wallet", "getnewaddress", &getnewaddress, true },
- { "wallet", "getrawchangeaddress", &getrawchangeaddress, true },
- { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false },
- { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false },
- { "wallet", "gettransaction", &gettransaction, false },
- { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false },
- { "wallet", "getwalletinfo", &getwalletinfo, false },
- { "wallet", "importprivkey", &importprivkey, true },
- { "wallet", "importwallet", &importwallet, true },
- { "wallet", "importaddress", &importaddress, true },
- { "wallet", "importprunedfunds", &importprunedfunds, true },
- { "wallet", "importpubkey", &importpubkey, true },
- { "wallet", "keypoolrefill", &keypoolrefill, true },
- { "wallet", "listaccounts", &listaccounts, false },
- { "wallet", "listaddressgroupings", &listaddressgroupings, false },
- { "wallet", "listlockunspent", &listlockunspent, false },
- { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false },
- { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false },
- { "wallet", "listsinceblock", &listsinceblock, false },
- { "wallet", "listtransactions", &listtransactions, false },
- { "wallet", "listunspent", &listunspent, false },
- { "wallet", "lockunspent", &lockunspent, true },
- { "wallet", "move", &movecmd, false },
- { "wallet", "sendfrom", &sendfrom, false },
- { "wallet", "sendmany", &sendmany, false },
- { "wallet", "sendtoaddress", &sendtoaddress, false },
- { "wallet", "setaccount", &setaccount, true },
- { "wallet", "settxfee", &settxfee, true },
- { "wallet", "signmessage", &signmessage, true },
- { "wallet", "walletlock", &walletlock, true },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, true },
- { "wallet", "walletpassphrase", &walletpassphrase, true },
- { "wallet", "removeprunedfunds", &removeprunedfunds, true },
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false, {"hexstring","options"} },
+ { "hidden", "resendwallettransactions", &resendwallettransactions, true, {} },
+ { "wallet", "abandontransaction", &abandontransaction, false, {"txid"} },
+ { "wallet", "abortrescan", &abortrescan, false, {} },
+ { "wallet", "addmultisigaddress", &addmultisigaddress, true, {"nrequired","keys","account"} },
+ { "wallet", "addwitnessaddress", &addwitnessaddress, true, {"address"} },
+ { "wallet", "backupwallet", &backupwallet, true, {"destination"} },
+ { "wallet", "bumpfee", &bumpfee, true, {"txid", "options"} },
+ { "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","include_unsafe","query_options"} },
+ { "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"} },
};
-void RegisterWalletRPCCommands(CRPCTable &tableRPC)
+void RegisterWalletRPCCommands(CRPCTable &t)
{
+ if (GetBoolArg("-disablewallet", false))
+ return;
+
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index a5de7e2de1..bd5dad18ca 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -6,7 +6,20 @@
#define BITCOIN_WALLET_RPCWALLET_H
class CRPCTable;
+class JSONRPCRequest;
-void RegisterWalletRPCCommands(CRPCTable &tableRPC);
+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 NULL if no wallet should be used, or a pointer to the CWallet
+ */
+CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest&);
+
+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 d075b2b641..1fe633f2e5 100644
--- a/src/wallet/test/accounting_tests.cpp
+++ b/src/wallet/test/accounting_tests.cpp
@@ -1,9 +1,8 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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 "wallet/wallet.h"
-#include "wallet/walletdb.h"
#include "wallet/test/wallet_test_fixture.h"
@@ -17,13 +16,13 @@ extern CWallet* pwalletMain;
BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup)
static void
-GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results)
+GetResults(std::map<CAmount, CAccountingEntry>& results)
{
std::list<CAccountingEntry> aes;
results.clear();
- BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK);
- walletdb.ListAccountCreditDebit("", aes);
+ BOOST_CHECK(pwalletMain->ReorderTransactions() == DB_LOAD_OK);
+ pwalletMain->ListAccountCreditDebit("", aes);
BOOST_FOREACH(CAccountingEntry& ae, aes)
{
results[ae.nOrderPos] = ae;
@@ -32,7 +31,6 @@ GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results)
BOOST_AUTO_TEST_CASE(acc_orderupgrade)
{
- CWalletDB walletdb(pwalletMain->strWalletFile);
std::vector<CWalletTx*> vpwtx;
CWalletTx wtx;
CAccountingEntry ae;
@@ -45,19 +43,19 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333333;
ae.strOtherAccount = "b";
ae.strComment = "";
- pwalletMain->AddAccountingEntry(ae, walletdb);
+ pwalletMain->AddAccountingEntry(ae);
wtx.mapValue["comment"] = "z";
- pwalletMain->AddToWallet(wtx, false, &walletdb);
+ pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[0]->nTimeReceived = (unsigned int)1333333335;
vpwtx[0]->nOrderPos = -1;
ae.nTime = 1333333336;
ae.strOtherAccount = "c";
- pwalletMain->AddAccountingEntry(ae, walletdb);
+ pwalletMain->AddAccountingEntry(ae);
- GetResults(walletdb, results);
+ GetResults(results);
BOOST_CHECK(pwalletMain->nOrderPosNext == 3);
BOOST_CHECK(2 == results.size());
@@ -71,9 +69,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333330;
ae.strOtherAccount = "d";
ae.nOrderPos = pwalletMain->IncOrderPosNext();
- pwalletMain->AddAccountingEntry(ae, walletdb);
+ pwalletMain->AddAccountingEntry(ae);
- GetResults(walletdb, results);
+ GetResults(results);
BOOST_CHECK(results.size() == 3);
BOOST_CHECK(pwalletMain->nOrderPosNext == 4);
@@ -88,9 +86,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
{
CMutableTransaction tx(wtx);
--tx.nLockTime; // Just to change the hash :)
- *static_cast<CTransaction*>(&wtx) = CTransaction(tx);
+ wtx.SetTx(MakeTransactionRef(std::move(tx)));
}
- pwalletMain->AddToWallet(wtx, false, &walletdb);
+ pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[1]->nTimeReceived = (unsigned int)1333333336;
@@ -98,14 +96,14 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
{
CMutableTransaction tx(wtx);
--tx.nLockTime; // Just to change the hash :)
- *static_cast<CTransaction*>(&wtx) = CTransaction(tx);
+ wtx.SetTx(MakeTransactionRef(std::move(tx)));
}
- pwalletMain->AddToWallet(wtx, false, &walletdb);
+ pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
vpwtx[2]->nOrderPos = -1;
- GetResults(walletdb, results);
+ GetResults(results);
BOOST_CHECK(results.size() == 3);
BOOST_CHECK(pwalletMain->nOrderPosNext == 6);
@@ -121,9 +119,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333334;
ae.strOtherAccount = "e";
ae.nOrderPos = -1;
- pwalletMain->AddAccountingEntry(ae, walletdb);
+ pwalletMain->AddAccountingEntry(ae);
- GetResults(walletdb, results);
+ GetResults(results);
BOOST_CHECK(results.size() == 4);
BOOST_CHECK(pwalletMain->nOrderPosNext == 7);
diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp
index 05387f5f2b..0d012dacad 100644
--- a/src/wallet/test/crypto_tests.cpp
+++ b/src/wallet/test/crypto_tests.cpp
@@ -1,8 +1,8 @@
-// Copyright (c) 2014 The Bitcoin Core developers
+// Copyright (c) 2014-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 "random.h"
+#include "test/test_random.h"
#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
#include "wallet/crypter.h"
@@ -42,15 +42,19 @@ bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char>
int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
vchCiphertext = std::vector<unsigned char> (nCLen);
- EVP_CIPHER_CTX ctx;
+ 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_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;
@@ -66,15 +70,19 @@ bool OldDecrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial
vchPlaintext = CKeyingMaterial(nPLen);
- EVP_CIPHER_CTX ctx;
+ 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_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;
@@ -97,10 +105,10 @@ static void TestPassphraseSingle(const std::vector<unsigned char>& vchSalt, cons
OldSetKeyFromPassphrase(passphrase, vchSalt, rounds, 0, chKey, chIV);
- BOOST_CHECK_MESSAGE(memcmp(chKey, crypt.chKey, sizeof(chKey)) == 0, \
- HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(crypt.chKey, crypt.chKey + (sizeof crypt.chKey)));
- BOOST_CHECK_MESSAGE(memcmp(chIV, crypt.chIV, sizeof(chIV)) == 0, \
- HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(crypt.chIV, crypt.chIV + (sizeof crypt.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, \
@@ -127,7 +135,7 @@ static void TestDecrypt(const CCrypter& crypt, const std::vector<unsigned char>&
CKeyingMaterial vchDecrypted2;
int result1, result2;
result1 = crypt.Decrypt(vchCiphertext, vchDecrypted1);
- result2 = OldDecrypt(vchCiphertext, vchDecrypted2, crypt.chKey, crypt.chIV);
+ 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
@@ -152,7 +160,7 @@ static void TestEncryptSingle(const CCrypter& crypt, const CKeyingMaterial& vchP
std::vector<unsigned char> vchCiphertext2;
int result1 = crypt.Encrypt(vchPlaintext, vchCiphertext1);
- int result2 = OldEncrypt(vchPlaintext, vchCiphertext2, crypt.chKey, crypt.chIV);
+ int result2 = OldEncrypt(vchPlaintext, vchCiphertext2, crypt.vchKey.data(), crypt.vchIV.data());
BOOST_CHECK(result1 == result2);
BOOST_CHECK(vchCiphertext1 == vchCiphertext2);
diff --git a/src/wallet/test/rpc_wallet_tests.cpp b/src/wallet/test/rpc_wallet_tests.cpp
deleted file mode 100644
index 4e7d177f51..0000000000
--- a/src/wallet/test/rpc_wallet_tests.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright (c) 2013-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 "rpc/server.h"
-#include "rpc/client.h"
-
-#include "base58.h"
-#include "main.h"
-#include "wallet/wallet.h"
-
-#include "wallet/test/wallet_test_fixture.h"
-
-#include <boost/algorithm/string.hpp>
-#include <boost/test/unit_test.hpp>
-
-#include <univalue.h>
-
-using namespace std;
-
-extern UniValue createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
-extern UniValue CallRPC(string args);
-
-extern CWallet* pwalletMain;
-
-BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, WalletTestingSetup)
-
-BOOST_AUTO_TEST_CASE(rpc_addmultisig)
-{
- rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
-
- // old, 65-byte-long:
- const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8";
- // new, compressed:
- const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
-
- UniValue v;
- CBitcoinAddress address;
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error);
-
- BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error);
-
- string short1(address1Hex, address1Hex + sizeof(address1Hex) - 2); // last byte missing
- BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error);
-
- string short2(address1Hex + 1, address1Hex + sizeof(address1Hex)); // first byte missing
- BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
-}
-
-BOOST_AUTO_TEST_CASE(rpc_wallet)
-{
- // Test RPC calls for various wallet statistics
- UniValue r;
- CPubKey demoPubkey;
- CBitcoinAddress demoAddress;
- UniValue retValue;
- string strAccount = "walletDemoAccount";
- CBitcoinAddress setaccountDemoAddress;
- {
- LOCK(pwalletMain->cs_wallet);
-
- demoPubkey = pwalletMain->GenerateNewKey();
- demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
- string strPurpose = "receive";
- BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
- CWalletDB walletdb(pwalletMain->strWalletFile);
- CAccount account;
- account.vchPubKey = demoPubkey;
- pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose);
- walletdb.WriteAccount(strAccount, account);
- });
-
- CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey();
- setaccountDemoAddress = CBitcoinAddress(CTxDestination(setaccountDemoPubkey.GetID()));
- }
- /*********************************
- * setaccount
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("setaccount " + setaccountDemoAddress.ToString() + " nullaccount"));
- /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ is not owned by the test wallet. */
- BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
- /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */
- BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error);
-
-
- /*********************************
- * getbalance
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getbalance"));
- BOOST_CHECK_NO_THROW(CallRPC("getbalance " + demoAddress.ToString()));
-
- /*********************************
- * listunspent
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
- BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error);
- BOOST_CHECK_NO_THROW(r = CallRPC("listunspent 0 1 []"));
- BOOST_CHECK(r.get_array().empty());
-
- /*********************************
- * listreceivedbyaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
-
- /*********************************
- * listreceivedbyaccount
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
-
- /*********************************
- * listsinceblock
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listsinceblock"));
-
- /*********************************
- * listtransactions
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions"));
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString()));
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " 20"));
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " 20 0"));
- BOOST_CHECK_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " not_int"), runtime_error);
-
- /*********************************
- * listlockunspent
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listlockunspent"));
-
- /*********************************
- * listaccounts
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listaccounts"));
-
- /*********************************
- * listaddressgroupings
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listaddressgroupings"));
-
- /*********************************
- * getrawchangeaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress"));
-
- /*********************************
- * getnewaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getnewaddress"));
- BOOST_CHECK_NO_THROW(CallRPC("getnewaddress getnewaddress_demoaccount"));
-
- /*********************************
- * getaccountaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\""));
- BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account
- BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
- BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get());
-
- /*********************************
- * getaccount
- *********************************/
- BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString()));
-
- /*********************************
- * signmessage + verifymessage
- *********************************/
- BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage"));
- BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error);
- /* Should throw error because this address is not loaded in the wallet */
- BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error);
-
- /* missing arguments */
- BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString()), runtime_error);
- BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str()), runtime_error);
- /* Illegal address */
- BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error);
- /* wrong address */
- BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false);
- /* Correct address and signature but wrong message */
- BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false);
- /* Correct address, message and signature*/
- BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true);
-
- /*********************************
- * getaddressesbyaccount
- *********************************/
- BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
- BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
- UniValue arr = retValue.get_array();
- BOOST_CHECK(arr.size() > 0);
- BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
-
- /*********************************
- * fundrawtransaction
- *********************************/
- BOOST_CHECK_THROW(CallRPC("fundrawtransaction 28z"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("fundrawtransaction 01000000000180969800000000001976a91450ce0a4b0ee0ddeb633da85199728b940ac3fe9488ac00000000"), runtime_error);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index 9036ee26d8..1989bf8d9b 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -1,3 +1,7 @@
+// Copyright (c) 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 "wallet/test/wallet_test_fixture.h"
#include "rpc/server.h"
@@ -10,7 +14,8 @@ WalletTestingSetup::WalletTestingSetup(const std::string& 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);
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index c6c5058984..8eeba72a06 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -9,10 +9,16 @@
#include <utility>
#include <vector>
+#include "rpc/server.h"
+#include "test/test_bitcoin.h"
+#include "validation.h"
#include "wallet/test/wallet_test_fixture.h"
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
+#include <univalue.h>
+
+extern UniValue importmulti(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 +27,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 +48,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, 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 +76,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 +84,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, 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, 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, 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, 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, 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 +111,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, 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, 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, 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, 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, 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, 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, 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, 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 +151,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, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, 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, 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, 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, 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, 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 +183,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, 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, 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 +202,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, 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, 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,16 +217,16 @@ 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, 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)
// they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change
empty_wallet();
- for (int i = 0; i < 20; i++)
+ for (int j = 0; j < 20; j++)
add_coin(50000 * COIN);
- BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, 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 +239,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, 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 +249,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, 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,22 +260,22 @@ 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, 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, 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);
// test with many inputs
for (CAmount amt=1500; amt < COIN; amt*=10) {
empty_wallet();
- // Create 676 inputs (= MAX_STANDARD_TX_SIZE / 148 bytes per input)
+ // 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, 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,17 +297,17 @@ 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, vCoins, setCoinsRet , nValueRet));
- BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 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;
- for (int i = 0; i < RANDOM_REPEATS; i++)
+ for (int j = 0; j < RANDOM_REPEATS; j++)
{
// 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, vCoins, setCoinsRet , nValueRet));
- BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 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++;
}
@@ -317,12 +323,12 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(25 * CENT);
fails = 0;
- for (int i = 0; i < RANDOM_REPEATS; i++)
+ for (int j = 0; j < RANDOM_REPEATS; j++)
{
// 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, vCoins, setCoinsRet , nValueRet));
- BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, 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 +343,7 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
CoinSet setCoinsRet;
CAmount nValueRet;
- LOCK(wallet.cs_wallet);
+ LOCK(testWallet.cs_wallet);
empty_wallet();
@@ -346,9 +352,167 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
add_coin(1000 * COIN);
add_coin(3 * COIN);
- BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 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();
+}
+
+BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
+{
+ LOCK(cs_main);
+
+ // Cap last block file size, and mine new block in a new block file.
+ 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;
+ LOCK(wallet.cs_wallet);
+ wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
+ BOOST_CHECK_EQUAL(oldTip, 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;
+ LOCK(wallet.cs_wallet);
+ wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
+ BOOST_CHECK_EQUAL(newTip, 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;
+ CWallet *backup = ::pwalletMain;
+ ::pwalletMain = &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);
+ 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\":\"Failed to rescan before time %d, transactions may be missing.\"}},{\"success\":true}]", newTip->GetBlockTimeMax()));
+ ::pwalletMain = backup;
+ }
+
+ // Verify ScanForWalletTransactions does not return null when the scan is
+ // elided due to the nTimeFirstKey optimization.
+ {
+ CWallet wallet;
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.UpdateTimeFirstKey(newTip->GetBlockTime() + 7200 + 1);
+ }
+ BOOST_CHECK_EQUAL(newTip, wallet.ScanForWalletTransactions(newTip));
+ }
+}
+
+// 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_SUITE_END()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 46ed542158..dcb452a009 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -8,18 +8,22 @@
#include "base58.h"
#include "checkpoints.h"
#include "chain.h"
-#include "coincontrol.h"
+#include "wallet/coincontrol.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
+#include "fs.h"
#include "key.h"
#include "keystore.h"
-#include "main.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"
@@ -29,17 +33,14 @@
#include <assert.h>
#include <boost/algorithm/string/replace.hpp>
-#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
-using namespace std;
-
CWallet* pwalletMain = NULL;
/** 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";
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
@@ -65,16 +66,16 @@ 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;
}
};
std::string COutput::ToString() const
{
- return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue));
+ return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue));
}
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
@@ -86,7 +87,7 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
return &(it->second);
}
-CPubKey CWallet::GenerateNewKey()
+CPubKey CWallet::GenerateNewKey(bool internal)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
@@ -98,44 +99,8 @@ CPubKey CWallet::GenerateNewKey()
CKeyMetadata metadata(nCreationTime);
// use HD key derivation if HD was enabled during wallet creation
- if (!hdChain.masterKeyID.IsNull()) {
- // 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 childKey; //key at m/0'/0'/<n>'
-
- // try to get the master key
- if (!GetKey(hdChain.masterKeyID, key))
- throw std::runtime_error("CWallet::GenerateNewKey(): Master key not found");
-
- masterKey.SetMaster(key.begin(), key.size());
-
- // derive m/0'
- // 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 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++;
- } while(HaveKey(childKey.key.GetPubKey().GetID()));
- secret = childKey.key;
-
- // update the chain model in the database
- if (!CWalletDB(strWalletFile).WriteHDChain(hdChain))
- throw std::runtime_error("CWallet::GenerateNewKey(): Writing HD chain model failed");
+ if (IsHDEnabled()) {
+ DeriveNewChildKey(metadata, secret, (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false));
} else {
secret.MakeNewKey(fCompressed);
}
@@ -148,14 +113,59 @@ CPubKey CWallet::GenerateNewKey()
assert(secret.VerifyPubKey(pubkey));
mapKeyMetadata[pubkey.GetID()] = metadata;
- if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
- nTimeFirstKey = nCreationTime;
+ UpdateTimeFirstKey(nCreationTime);
if (!AddKeyPubKey(secret, pubkey))
- throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
+ throw std::runtime_error(std::string(__func__) + ": AddKey failed");
return pubkey;
}
+void CWallet::DeriveNewChildKey(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 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
+ if (!GetKey(hdChain.masterKeyID, key))
+ throw std::runtime_error(std::string(__func__) + ": Master key not found");
+
+ masterKey.SetMaster(key.begin(), key.size());
+
+ // derive m/0'
+ // use hardened derivation (child keys >= 0x80000000 are hardened after bip32)
+ masterKey.Derive(accountKey, 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
+ 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(*dbw).WriteHDChain(hdChain))
+ throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
+}
+
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
@@ -171,10 +181,8 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
if (HaveWatchOnly(script))
RemoveWatchOnly(script);
- if (!fFileBacked)
- return true;
if (!IsCrypted()) {
- return CWalletDB(strWalletFile).WriteKey(pubkey,
+ return CWalletDB(*dbw).WriteKey(pubkey,
secret.GetPrivKey(),
mapKeyMetadata[pubkey.GetID()]);
}
@@ -182,12 +190,10 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &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)
@@ -195,20 +201,18 @@ 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;
}
@@ -217,13 +221,23 @@ bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigne
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
}
+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)
@@ -242,15 +256,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)
@@ -260,9 +279,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;
}
@@ -275,7 +293,7 @@ bool CWallet::LoadWatchOnly(const CScript &dest)
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
CCrypter crypter;
- CKeyingMaterial vMasterKey;
+ CKeyingMaterial _vMasterKey;
{
LOCK(cs_wallet);
@@ -283,9 +301,9 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
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;
}
}
@@ -301,14 +319,14 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
Lock();
CCrypter crypter;
- CKeyingMaterial vMasterKey;
+ CKeyingMaterial _vMasterKey;
BOOST_FOREACH(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);
@@ -325,9 +343,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;
@@ -340,7 +358,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
void CWallet::SetBestChain(const CBlockLocator& loc)
{
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
walletdb.WriteBestBlock(loc);
}
@@ -359,9 +377,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)
@@ -383,9 +400,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);
@@ -395,79 +412,62 @@ set<uint256> CWallet::GetConflicts(const uint256& txid) const
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (mapTxSpends.count(txin.prevout) <= 1)
continue; // No conflict if zero or one spends
range = mapTxSpends.equal_range(txin.prevout);
- for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
- result.insert(it->second);
+ for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
+ result.insert(_it->second);
}
return result;
}
+bool CWallet::HasWalletSpend(const uint256& txid) const
+{
+ AssertLockHeld(cs_wallet);
+ auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0));
+ return (iter != mapTxSpends.end() && iter->first.hash == txid);
+}
+
void CWallet::Flush(bool shutdown)
{
- bitdb.Flush(shutdown);
+ dbw->Flush(shutdown);
}
bool CWallet::Verify()
{
- LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
- std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
+ if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
+ return true;
- LogPrintf("Using wallet %s\n", walletFile);
uiInterface.InitMessage(_("Verifying wallet..."));
+ std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
- // 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()));
+ std::string strError;
+ if (!CWalletDB::VerifyEnvironment(walletFile, GetDataDir().string(), strError))
+ return InitError(strError);
- 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))
+ CWallet dummyWallet;
+ if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter))
return false;
}
-
- if (boost::filesystem::exists(GetDataDir() / walletFile))
+
+ std::string strWarning;
+ bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetDataDir().string(), strWarning, strError);
+ if (!strWarning.empty())
+ InitWarning(strWarning);
+ if (!dbV)
{
- 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));
+ InitError(strError);
+ return false;
}
-
return true;
}
-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).
@@ -511,7 +511,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)
@@ -529,9 +529,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);
}
@@ -544,7 +544,7 @@ void CWallet::AddToSpends(const uint256& wtxid)
if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
return;
- BOOST_FOREACH(const CTxIn& txin, thisTx.vin)
+ BOOST_FOREACH(const CTxIn& txin, thisTx.tx->vin)
AddToSpends(txin.prevout, wtxid);
}
@@ -553,10 +553,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;
@@ -579,30 +579,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 = NULL;
+ 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);
@@ -611,27 +606,32 @@ 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 = NULL;
+
Lock();
Unlock(strWalletPassphrase);
+
+ // if we are using HD, replace the HD master key (seed) with a new one
+ if (IsHDEnabled()) {
+ if (!SetHDMasterKey(GenerateNewHDMasterKey())) {
+ return false;
+ }
+ }
+
NewKeyPool();
Lock();
// 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);
@@ -639,6 +639,83 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
return true;
}
+DBErrors CWallet::ReorderTransactions()
+{
+ LOCK(cs_wallet);
+ 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 std::pair<CWalletTx*, CAccountingEntry*> TxPair;
+ typedef std::multimap<int64_t, TxPair > TxItems;
+ TxItems txByTime;
+
+ for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ CWalletTx* wtx = &((*it).second);
+ txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
+ }
+ std::list<CAccountingEntry> acentries;
+ walletdb.ListAccountCreditDebit("", acentries);
+ BOOST_FOREACH(CAccountingEntry& entry, acentries)
+ {
+ txByTime.insert(std::make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
+ }
+
+ nOrderPosNext = 0;
+ std::vector<int64_t> nOrderPosOffsets;
+ for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
+ {
+ CWalletTx *const pwtx = (*it).second.first;
+ CAccountingEntry *const pacentry = (*it).second.second;
+ int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;
+
+ if (nOrderPos == -1)
+ {
+ nOrderPos = nOrderPosNext++;
+ nOrderPosOffsets.push_back(nOrderPos);
+
+ if (pwtx)
+ {
+ if (!walletdb.WriteTx(*pwtx))
+ return DB_LOAD_FAIL;
+ }
+ else
+ if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
+ return DB_LOAD_FAIL;
+ }
+ else
+ {
+ int64_t nOrderPosOff = 0;
+ BOOST_FOREACH(const int64_t& nOffsetStart, nOrderPosOffsets)
+ {
+ if (nOrderPos >= nOffsetStart)
+ ++nOrderPosOff;
+ }
+ nOrderPos += nOrderPosOff;
+ nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
+
+ if (!nOrderPosOff)
+ continue;
+
+ // Since we're changing the order, write it back
+ if (pwtx)
+ {
+ if (!walletdb.WriteTx(*pwtx))
+ return DB_LOAD_FAIL;
+ }
+ else
+ if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
+ return DB_LOAD_FAIL;
+ }
+ }
+ walletdb.WriteOrderPosNext(nOrderPosNext);
+
+ return DB_LOAD_OK;
+}
+
int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
{
AssertLockHeld(cs_wallet); // nOrderPosNext
@@ -646,14 +723,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;
@@ -667,7 +744,7 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun
debit.nTime = nNow;
debit.strOtherAccount = strTo;
debit.strComment = strComment;
- AddAccountingEntry(debit, walletdb);
+ AddAccountingEntry(debit, &walletdb);
// Credit
CAccountingEntry credit;
@@ -677,7 +754,7 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun
credit.nTime = nNow;
credit.strOtherAccount = strFrom;
credit.strComment = strComment;
- AddAccountingEntry(credit, walletdb);
+ AddAccountingEntry(credit, &walletdb);
if (!walletdb.TxnCommit())
return false;
@@ -687,7 +764,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);
@@ -698,10 +775,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.vout)
+ BOOST_FOREACH(const CTxOut& txout, (*it).second.tx->vout)
if (txout.scriptPubKey == scriptPubKey) {
bForceNew = true;
break;
@@ -711,7 +788,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");
@@ -732,158 +809,157 @@ void CWallet::MarkDirty()
}
}
-bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb)
+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(*dbw, "r+", fFlushOnClose);
+
uint256 hash = wtxIn.GetHash();
- if (fFromLoadWallet)
- {
- mapWallet[hash] = wtxIn;
- CWalletTx& wtx = mapWallet[hash];
- wtx.BindWallet(this);
- wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
+ // Inserts only if not already there, returns tx inserted or tx found
+ 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;
+ if (fInsertedNew)
+ {
+ wtx.nTimeReceived = GetAdjustedTime();
+ wtx.nOrderPos = IncOrderPosNext(&walletdb);
+ wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
+ wtx.nTimeSmart = ComputeTimeSmart(wtx);
AddToSpends(hash);
- BOOST_FOREACH(const CTxIn& txin, wtx.vin) {
- if (mapWallet.count(txin.prevout.hash)) {
- CWalletTx& prevtx = mapWallet[txin.prevout.hash];
- if (prevtx.nIndex == -1 && !prevtx.hashUnset()) {
- MarkConflicted(prevtx.hashBlock, wtx.GetHash());
- }
- }
- }
}
- else
- {
- LOCK(cs_wallet);
- // 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));
- CWalletTx& wtx = (*ret.first).second;
- wtx.BindWallet(this);
- bool fInsertedNew = ret.second;
- if (fInsertedNew)
- {
- wtx.nTimeReceived = GetAdjustedTime();
- wtx.nOrderPos = IncOrderPosNext(pwalletdb);
- 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());
- }
- AddToSpends(hash);
+ bool fUpdated = false;
+ if (!fInsertedNew)
+ {
+ // Merge
+ if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock)
+ {
+ wtx.hashBlock = wtxIn.hashBlock;
+ fUpdated = true;
}
-
- bool fUpdated = false;
- if (!fInsertedNew)
+ // If no longer abandoned, update
+ if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned())
{
- // Merge
- if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock)
- {
- wtx.hashBlock = wtxIn.hashBlock;
- fUpdated = true;
- }
- // If no longer abandoned, update
- if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned())
- {
- wtx.hashBlock = wtxIn.hashBlock;
- fUpdated = true;
- }
- if (wtxIn.nIndex != -1 && (wtxIn.nIndex != wtx.nIndex))
- {
- wtx.nIndex = wtxIn.nIndex;
- fUpdated = true;
- }
- if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
- {
- wtx.fFromMe = wtxIn.fFromMe;
- fUpdated = true;
- }
+ wtx.hashBlock = wtxIn.hashBlock;
+ fUpdated = true;
}
+ if (wtxIn.nIndex != -1 && (wtxIn.nIndex != wtx.nIndex))
+ {
+ wtx.nIndex = wtxIn.nIndex;
+ fUpdated = true;
+ }
+ if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
+ {
+ wtx.fFromMe = wtxIn.fFromMe;
+ fUpdated = true;
+ }
+ }
- //// debug print
- LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
+ //// debug print
+ LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
- // Write to disk
- if (fInsertedNew || fUpdated)
- if (!pwalletdb->WriteTx(wtx))
- return false;
+ // Write to disk
+ if (fInsertedNew || fUpdated)
+ if (!walletdb.WriteTx(wtx))
+ return false;
- // Break debit/credit balance caches:
- wtx.MarkDirty();
+ // Break debit/credit balance caches:
+ wtx.MarkDirty();
- // Notify UI of new or updated transaction
- NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+ // Notify UI of new or updated transaction
+ 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", "");
+ // notify an external script when a wallet transaction comes in or is updated
+ std::string strCmd = GetArg("-walletnotify", "");
- if ( !strCmd.empty())
- {
- boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
- boost::thread t(runCommand, strCmd); // thread runs free
- }
+ if ( !strCmd.empty())
+ {
+ boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+
+ return true;
+}
+
+bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
+{
+ uint256 hash = wtxIn.GetHash();
+ mapWallet[hash] = wtxIn;
+ CWalletTx& wtx = mapWallet[hash];
+ wtx.BindWallet(this);
+ wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
+ AddToSpends(hash);
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) {
+ if (mapWallet.count(txin.prevout.hash)) {
+ CWalletTx& prevtx = mapWallet[txin.prevout.hash];
+ if (prevtx.nIndex == -1 && !prevtx.hashUnset()) {
+ MarkConflicted(prevtx.hashBlock, wtx.GetHash());
+ }
+ }
}
+
return true;
}
/**
- * 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 == NULL, 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 CBlock* pblock, bool fUpdate)
+bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
{
+ const CTransaction& tx = *ptx;
{
AssertLockHeld(cs_wallet);
- if (pblock) {
+ if (pIndex != NULL) {
BOOST_FOREACH(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()) {
- LogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pblock->GetHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
- MarkConflicted(pblock->GetHash(), range.first->second);
+ LogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pIndex->GetBlockHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
+ MarkConflicted(pIndex->GetBlockHash(), range.first->second);
}
range.first++;
}
@@ -894,17 +970,13 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
{
- CWalletTx wtx(this,tx);
+ CWalletTx wtx(this, ptx);
// Get merkle branch if transaction was found in a block
- if (pblock)
- wtx.SetMerkleBranch(*pblock);
+ if (pIndex != NULL)
+ wtx.SetMerkleBranch(pIndex, posInBlock);
- // Do not flush the wallet here for performance reasons
- // this is safe, as in case of a crash, we rescan the necessary blocks on startup through our SetBestChain-mechanism
- CWalletDB walletdb(strWalletFile, "r+", false);
-
- return AddToWallet(wtx, false, &walletdb);
+ return AddToWallet(wtx, false);
}
}
return false;
@@ -914,8 +986,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
{
LOCK2(cs_main, cs_wallet);
- // Do not flush the wallet here for performance reasons
- CWalletDB walletdb(strWalletFile, "r+", false);
+ CWalletDB walletdb(*dbw, "r+");
std::set<uint256> todo;
std::set<uint256> done;
@@ -957,7 +1028,7 @@ 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.vin)
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (mapWallet.count(txin.prevout.hash))
mapWallet[txin.prevout.hash].MarkDirty();
@@ -987,7 +1058,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;
@@ -1018,7 +1089,7 @@ 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.vin)
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (mapWallet.count(txin.prevout.hash))
mapWallet[txin.prevout.hash].MarkDirty();
@@ -1027,11 +1098,10 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
}
-void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock)
-{
- LOCK2(cs_main, cs_wallet);
+void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pindex, int posInBlock) {
+ const CTransaction& tx = *ptx;
- if (!AddToWalletIfInvolvingMe(tx, pblock, true))
+ if (!AddToWalletIfInvolvingMe(ptx, pindex, posInBlock, true))
return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
@@ -1044,33 +1114,67 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex,
}
}
+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;
- if (txin.prevout.n < prev.vout.size())
- return IsMine(prev.vout[txin.prevout.n]);
+ if (txin.prevout.n < prev.tx->vout.size())
+ return IsMine(prev.tx->vout[txin.prevout.n]);
}
}
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;
- if (txin.prevout.n < prev.vout.size())
- if (IsMine(prev.vout[txin.prevout.n]) & filter)
- return prev.vout[txin.prevout.n].nValue;
+ if (txin.prevout.n < prev.tx->vout.size())
+ if (IsMine(prev.tx->vout[txin.prevout.n]) & filter)
+ return prev.tx->vout[txin.prevout.n].nValue;
}
}
return 0;
@@ -1084,7 +1188,7 @@ isminetype CWallet::IsMine(const CTxOut& txout) const
CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const
{
if (!MoneyRange(txout.nValue))
- throw std::runtime_error("CWallet::GetCredit(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
return ((IsMine(txout) & filter) ? txout.nValue : 0);
}
@@ -1113,7 +1217,7 @@ bool CWallet::IsChange(const CTxOut& txout) const
CAmount CWallet::GetChange(const CTxOut& txout) const
{
if (!MoneyRange(txout.nValue))
- throw std::runtime_error("CWallet::GetChange(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
return (IsChange(txout) ? txout.nValue : 0);
}
@@ -1137,11 +1241,32 @@ CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) co
{
nDebit += GetDebit(txin, filter);
if (!MoneyRange(nDebit))
- throw std::runtime_error("CWallet::GetDebit(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nDebit;
}
+bool CWallet::IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const
+{
+ LOCK(cs_wallet);
+
+ BOOST_FOREACH(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;
@@ -1149,7 +1274,7 @@ CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) c
{
nCredit += GetCredit(txout, filter);
if (!MoneyRange(nCredit))
- throw std::runtime_error("CWallet::GetCredit(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nCredit;
}
@@ -1161,26 +1286,49 @@ CAmount CWallet::GetChange(const CTransaction& tx) const
{
nChange += GetChange(txout);
if (!MoneyRange(nChange))
- throw std::runtime_error("CWallet::GetChange(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nChange;
}
-bool CWallet::SetHDMasterKey(const CKey& key)
+CPubKey CWallet::GenerateNewHDMasterKey()
{
- LOCK(cs_wallet);
+ CKey key;
+ key.MakeNewKey(true);
+
+ int64_t nCreationTime = GetTime();
+ CKeyMetadata metadata(nCreationTime);
- // store the key as normal "key"/"ckey" object
- // in the database
- // key metadata is not required
+ // calculate the pubkey
CPubKey pubkey = key.GetPubKey();
- if (!AddKeyPubKey(key, pubkey))
- throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
+ assert(key.VerifyPubKey(pubkey));
+
+ // set the hd keypath to "m" -> Master, refers the masterkeyid to itself
+ metadata.hdKeypath = "m";
+ metadata.hdMasterKeyID = pubkey.GetID();
+
+ {
+ LOCK(cs_wallet);
+
+ // mem store the metadata
+ mapKeyMetadata[pubkey.GetID()] = metadata;
+
+ // write the key&metadata to the database
+ if (!AddKeyPubKey(key, pubkey))
+ throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed");
+ }
+ return pubkey;
+}
+
+bool CWallet::SetHDMasterKey(const CPubKey& pubkey)
+{
+ LOCK(cs_wallet);
// 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);
@@ -1190,13 +1338,18 @@ bool CWallet::SetHDMasterKey(const CKey& key)
bool CWallet::SetHDChain(const CHDChain& chain, bool memonly)
{
LOCK(cs_wallet);
- if (!memonly && !CWalletDB(strWalletFile).WriteHDChain(chain))
- throw runtime_error("AddHDChain(): 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() const
+{
+ return !hdChain.masterKeyID.IsNull();
+}
+
int64_t CWalletTx::GetTxTime() const
{
int64_t n = nTimeSmart;
@@ -1214,7 +1367,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;
}
@@ -1222,7 +1375,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;
@@ -1230,9 +1383,9 @@ 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);
- if (mi != pwallet->mapRequestCount.end())
- nRequests = (*mi).second;
+ std::map<uint256, int>::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock);
+ if (_mi != pwallet->mapRequestCount.end())
+ nRequests = (*_mi).second;
else
nRequests = 1; // If it's in someone else's block it must have got out
}
@@ -1242,8 +1395,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();
@@ -1254,14 +1407,14 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
CAmount nDebit = GetDebit(filter);
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
- CAmount nValueOut = GetValueOut();
+ CAmount nValueOut = tx->GetValueOut();
nFee = nDebit - nValueOut;
}
// Sent/received.
- for (unsigned int i = 0; i < vout.size(); ++i)
+ for (unsigned int i = 0; i < tx->vout.size(); ++i)
{
- const CTxOut& txout = vout[i];
+ const CTxOut& txout = tx->vout[i];
isminetype fIsMine = pwallet->IsMine(txout);
// Only need to handle txouts if AT LEAST one of these is true:
// 1) they debit from us (sent)
@@ -1298,83 +1451,64 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
}
-void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
- CAmount& nSent, CAmount& nFee, const isminefilter& filter) const
-{
- nReceived = nSent = nFee = 0;
-
- CAmount allFee;
- string strSentAccount;
- list<COutputEntry> listReceived;
- list<COutputEntry> listSent;
- GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
-
- 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;
- }
- }
- }
-}
-
/**
* 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 pointer to the first block in the last contiguous range that was
+ * successfully scanned or elided (elided if pIndexStart points at a block
+ * before CWallet::nTimeFirstKey). Returns null if there is no such range, or
+ * the range doesn't include chainActive.Tip().
*/
-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 = pindexStart;
{
LOCK2(cs_main, cs_wallet);
+ fAbortRescan = false;
+ fScanningWallet = true;
// 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)))
+ while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - TIMESTAMP_WINDOW)))
pindex = chainActive.Next(pindex);
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
- double dProgressStart = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false);
- double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip(), false);
- while (pindex)
+ double dProgressStart = GuessVerificationProgress(chainParams.TxData(), pindex);
+ double dProgressTip = GuessVerificationProgress(chainParams.TxData(), chainActive.Tip());
+ while (pindex && !fAbortRescan)
{
if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0)
- ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
+ ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((GuessVerificationProgress(chainParams.TxData(), pindex) - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
+ if (GetTime() >= nNow + 60) {
+ nNow = GetTime();
+ LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex));
+ }
CBlock block;
- ReadBlockFromDisk(block, pindex, Params().GetConsensus());
- BOOST_FOREACH(CTransaction& tx, block.vtx)
- {
- if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
- ret++;
+ if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) {
+ for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
+ AddToWalletIfInvolvingMe(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
+ }
+ if (!ret) {
+ ret = pindex;
+ }
+ } else {
+ ret = nullptr;
}
pindex = chainActive.Next(pindex);
- if (GetTime() >= nNow + 60) {
- nNow = GetTime();
- LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), 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;
}
@@ -1407,27 +1541,36 @@ void CWallet::ReacceptWalletTransactions()
CWalletTx& wtx = *(item.second);
LOCK(mempool.cs);
- wtx.AcceptToMemoryPool(false, maxTxFee);
+ CValidationState state;
+ wtx.AcceptToMemoryPool(maxTxFee, state);
}
}
-bool CWalletTx::RelayWalletTransaction()
+bool CWalletTx::RelayWalletTransaction(CConnman* connman)
{
assert(pwallet->GetBroadcastTransactions());
- if (!IsCoinBase())
+ if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain() == 0)
{
- if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
+ CValidationState state;
+ /* GetDepthInMainChain already catches known conflicts. */
+ if (InMempool() || AcceptToMemoryPool(maxTxFee, state)) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
- RelayTransaction((CTransaction)*this);
- return true;
+ if (connman) {
+ CInv inv(MSG_TX, GetHash());
+ connman->ForEachNode([&inv](CNode* pnode)
+ {
+ pnode->PushInventory(inv);
+ });
+ return true;
+ }
}
}
return false;
}
-set<uint256> CWalletTx::GetConflicts() const
+std::set<uint256> CWalletTx::GetConflicts() const
{
- set<uint256> result;
+ std::set<uint256> result;
if (pwallet != NULL)
{
uint256 myHash = GetHash();
@@ -1439,7 +1582,7 @@ set<uint256> CWalletTx::GetConflicts() const
CAmount CWalletTx::GetDebit(const isminefilter& filter) const
{
- if (vin.empty())
+ if (tx->vin.empty())
return 0;
CAmount debit = 0;
@@ -1474,7 +1617,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const
if (IsCoinBase() && GetBlocksToMaturity() > 0)
return 0;
- int64_t credit = 0;
+ CAmount credit = 0;
if (filter & ISMINE_SPENDABLE)
{
// GetBalance can assume transactions in mapWallet won't change
@@ -1529,11 +1672,11 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
CAmount nCredit = 0;
uint256 hashTx = GetHash();
- for (unsigned int i = 0; i < vout.size(); i++)
+ for (unsigned int i = 0; i < tx->vout.size(); i++)
{
if (!pwallet->IsSpent(hashTx, i))
{
- const CTxOut &txout = vout[i];
+ 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");
@@ -1572,11 +1715,11 @@ CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
return nAvailableWatchCreditCached;
CAmount nCredit = 0;
- for (unsigned int i = 0; i < vout.size(); i++)
+ for (unsigned int i = 0; i < tx->vout.size(); i++)
{
if (!pwallet->IsSpent(GetHash(), i))
{
- const CTxOut &txout = vout[i];
+ 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");
@@ -1600,10 +1743,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
@@ -1624,53 +1764,53 @@ bool CWalletTx::IsTrusted() const
return false;
// Trusted if all inputs are from us and are in the mempool:
- BOOST_FOREACH(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, tx->vin)
{
// Transactions not sent by us: not trusted
const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
if (parent == NULL)
return false;
- const CTxOut& parentOut = parent->vout[txin.prevout.n];
+ const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
return false;
}
return true;
}
-bool CWalletTx::IsEquivalentTo(const CWalletTx& tx) const
+bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
{
- CMutableTransaction tx1 = *this;
- CMutableTransaction tx2 = tx;
+ 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();
return CTransaction(tx1) == CTransaction(tx2);
}
-std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
+std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman)
{
std::vector<uint256> result;
LOCK(cs_wallet);
// Sort them in chronological order
- multimap<unsigned int, CWalletTx*> mapSorted;
+ std::multimap<unsigned int, CWalletTx*> mapSorted;
BOOST_FOREACH(PAIRTYPE(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)
{
CWalletTx& wtx = *item.second;
- if (wtx.RelayWalletTransaction())
+ if (wtx.RelayWalletTransaction(connman))
result.push_back(wtx.GetHash());
}
return result;
}
-void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
+void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman)
{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
@@ -1688,7 +1828,7 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
// Rebroadcast unconfirmed txes older than 5 minutes before the last
// block was found:
- std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60);
+ std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60, connman);
if (!relayed.empty())
LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
}
@@ -1709,7 +1849,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())
@@ -1725,7 +1865,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())
@@ -1740,7 +1880,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();
@@ -1754,7 +1894,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())
@@ -1770,7 +1910,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())
@@ -1785,7 +1925,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();
@@ -1794,13 +1934,59 @@ 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;
+}
+
+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;
@@ -1808,9 +1994,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;
@@ -1823,29 +2006,97 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (nDepth == 0 && !pcoin->InMempool())
continue;
- for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
- isminetype mine = IsMine(pcoin->vout[i]);
- if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
- !IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) &&
- (!coinControl || !coinControl->HasSelected() || coinControl->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));
+ 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 (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;
+ }
}
}
}
}
-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)
+static void ApproximateBestSubset(const std::vector<CInputCoin>& vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
+ std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
{
- vector<char> vfIncluded;
+ std::vector<char> vfIncluded;
vfBest.assign(vValue.size(), true);
nBest = nTotalLower;
- seed_insecure_rand();
+ FastRandomContext insecure_rand;
for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
{
@@ -1862,9 +2113,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()&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)
{
@@ -1874,7 +2125,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;
}
}
@@ -1883,17 +2134,15 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
}
}
-bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, 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);
@@ -1908,23 +2157,25 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
continue;
+ if (!mempool.TransactionWithinChainLimit(pcoin->GetHash(), nMaxAncestors))
+ continue;
+
int i = output.i;
- CAmount n = pcoin->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;
}
@@ -1934,25 +2185,25 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
{
for (unsigned int i = 0; i < vValue.size(); ++i)
{
- setCoinsRet.insert(vValue[i].second);
- nValueRet += vValue[i].first;
+ setCoinsRet.insert(vValue[i]);
+ nValueRet += vValue[i].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);
@@ -1961,33 +2212,37 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
// 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)
@@ -1996,14 +2251,14 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
{
if (!out.fSpendable)
continue;
- nValueRet += out.tx->vout[out.i].nValue;
- setCoinsRet.insert(make_pair(out.tx, out.i));
+ nValueRet += out.tx->tx->vout[out.i].nValue;
+ 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;
@@ -2011,32 +2266,39 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
coinControl->ListSelected(vPresetInputs);
BOOST_FOREACH(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;
// Clearly invalid input, fail
- if (pcoin->vout.size() <= outpoint.n)
+ if (pcoin->tx->vout.size() <= outpoint.n)
return false;
- nValueFromPresetInputs += pcoin->vout[outpoint.n].nValue;
- setPresetCoins.insert(make_pair(pcoin, outpoint.n));
+ nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue;
+ 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);
+
bool res = nTargetValue <= nValueFromPresetInputs ||
- SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, vCoins, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, vCoins, setCoinsRet, nValueRet) ||
- (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, vCoins, setCoinsRet, nValueRet));
+ SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet) ||
+ SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet) ||
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet)) ||
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet)) ||
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet)) ||
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet)) ||
+ (bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::numeric_limits<uint64_t>::max(), vCoins, setCoinsRet, nValueRet));
// because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
@@ -2047,14 +2309,37 @@ 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 CTxDestination& destChange)
+bool CWallet::SignTransaction(CMutableTransaction &tx)
{
- vector<CRecipient> vecSend;
+ // sign the new tx
+ CTransaction txNewConst(tx);
+ int nIn = 0;
+ for (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, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, bool keepReserveKey, const CTxDestination& destChange)
+{
+ std::vector<CRecipient> vecSend;
// Turn the txout set into a CRecipient vector
- BOOST_FOREACH(const CTxOut& txOut, tx.vout)
+ for (size_t idx = 0; idx < tx.vout.size(); idx++)
{
- CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false};
+ const CTxOut& txOut = tx.vout[idx];
+ CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, setSubtractFeeFromOutputs.count(idx) == 1};
vecSend.push_back(recipient);
}
@@ -2074,10 +2359,14 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
return false;
if (nChangePosInOut != -1)
- tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.vout[nChangePosInOut]);
+ tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]);
+
+ // 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.vin)
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (!coinControl.IsSelected(txin.prevout))
{
@@ -2091,20 +2380,24 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
}
}
+ // optionally keep the change output key
+ if (keepReserveKey)
+ reservekey.KeepKey();
+
return true;
}
-bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
+bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign)
{
CAmount nValue = 0;
int nChangePosRequest = nChangePosInOut;
unsigned int nSubtractFeeFromAmount = 0;
- BOOST_FOREACH (const CRecipient& recipient, vecSend)
+ for (const auto& recipient : vecSend)
{
if (nValue < 0 || recipient.nAmount < 0)
{
- strFailReason = _("Transaction amounts must be positive");
+ strFailReason = _("Transaction amounts must not be negative");
return false;
}
nValue += recipient.nAmount;
@@ -2112,9 +2405,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
if (recipient.fSubtractFeeFromAmount)
nSubtractFeeFromAmount++;
}
- if (vecSend.empty() || nValue < 0)
+ if (vecSend.empty())
{
- strFailReason = _("Transaction amounts must be positive");
+ strFailReason = _("Transaction must have at least one recipient");
return false;
}
@@ -2155,6 +2448,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
{
+ std::set<CInputCoin> setCoins;
LOCK2(cs_main, cs_wallet);
{
std::vector<COutput> vAvailableCoins;
@@ -2173,9 +2467,8 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
CAmount nValueToSelect = nValue;
if (nSubtractFeeFromAmount == 0)
nValueToSelect += nFeeRet;
- double dPriority = 0;
// vouts to the payees
- BOOST_FOREACH (const CRecipient& recipient, vecSend)
+ for (const auto& recipient : vecSend)
{
CTxOut txout(recipient.nAmount, recipient.scriptPubKey);
@@ -2190,7 +2483,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
}
- if (txout.IsDust(::minRelayTxFee))
+ if (IsDust(txout, ::dustRelayFee))
{
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
{
@@ -2207,26 +2500,13 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
// Choose coins to use
- set<pair<const CWalletTx*,unsigned int> > setCoins;
CAmount nValueIn = 0;
+ setCoins.clear();
if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
{
strFailReason = _("Insufficient funds");
return false;
}
- BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
- {
- CAmount nCredit = pcoin.first->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;
- }
const CAmount nChange = nValueIn - nValueToSelect;
if (nChange > 0)
@@ -2253,8 +2533,12 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Reserve a new key pair from key pool
CPubKey vchPubKey;
bool ret;
- ret = reservekey.GetReservedKey(vchPubKey);
- assert(ret); // should never fail, as we just unlocked
+ ret = reservekey.GetReservedKey(vchPubKey, true);
+ if (!ret)
+ {
+ strFailReason = _("Keypool ran out, please call keypoolrefill first");
+ return false;
+ }
scriptChange = GetScriptForDestination(vchPubKey.GetID());
}
@@ -2264,16 +2548,16 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// 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(::minRelayTxFee))
+ if (nSubtractFeeFromAmount > 0 && IsDust(newTxOut, ::dustRelayFee))
{
- CAmount nDust = newTxOut.GetDustThreshold(::minRelayTxFee) - newTxOut.nValue;
+ CAmount nDust = GetDustThreshold(newTxOut, ::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(::minRelayTxFee))
+ if (IsDust(txNew.vout[i], ::dustRelayFee))
{
strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
return false;
@@ -2285,7 +2569,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Never create dust outputs; if we would, just
// add the dust to the fee.
- if (newTxOut.IsDust(::minRelayTxFee))
+ if (IsDust(newTxOut, ::dustRelayFee))
{
nChangePosInOut = -1;
nFeeRet += nChange;
@@ -2304,77 +2588,51 @@ 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
+ } else {
reservekey.ReturnKey();
+ nChangePosInOut = -1;
+ }
// Fill vin
//
- // Note how the sequence number is set to max()-1 so that the
- // nLockTime set above actually works.
- BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
- std::numeric_limits<unsigned int>::max()-1));
-
- // Sign
- int nIn = 0;
- CTransaction txNewConst(txNew);
- BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- {
- bool signSuccess;
- const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
- SignatureData sigdata;
- if (sign)
- signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata);
- else
- signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata);
-
- if (!signSuccess)
- {
- strFailReason = _("Signing transaction failed");
- return false;
- } else {
- UpdateTransaction(txNew, nIn, sigdata);
- }
-
- nIn++;
+ // Note how the sequence number is set to non-maxint so that
+ // the nLockTime set above actually works.
+ //
+ // 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 possible change from prior
+ // behavior."
+ bool rbf = coinControl ? coinControl->signalRbf : fWalletRbf;
+ for (const auto& coin : setCoins)
+ txNew.vin.push_back(CTxIn(coin.outpoint,CScript(),
+ std::numeric_limits<unsigned int>::max() - (rbf ? 2 : 1)));
+
+ // Fill in dummy signatures for fee calculation.
+ if (!DummySignTx(txNew, setCoins)) {
+ strFailReason = _("Signing transaction failed");
+ return false;
}
unsigned int nBytes = GetVirtualTransactionSize(txNew);
- // Remove scriptSigs if we used dummy signatures for fee calculation
- if (!sign) {
- BOOST_FOREACH (CTxIn& vin, txNew.vin)
- vin.scriptSig = CScript();
- txNew.wit.SetNull();
- }
-
- // Embed the constructed transaction data in wtxNew.
- *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
+ CTransaction txNewConst(txNew);
- // Limit size
- if (GetTransactionCost(txNew) >= MAX_STANDARD_TX_COST)
- {
- strFailReason = _("Transaction too large");
- return false;
+ // Remove scriptSigs to eliminate the fee calculation dummy signatures
+ for (auto& vin : txNew.vin) {
+ vin.scriptSig = CScript();
+ vin.scriptWitness.SetNull();
}
- dPriority = wtxNew.ComputePriority(dPriority, nBytes);
+ // 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(nTxConfirmTarget);
- // Require at least hard-coded AllowFree.
- if (dPriority >= dPriorityNeeded && AllowFree(dPriority))
- break;
- }
-
- CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
+ CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator);
if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) {
nFeeNeeded = coinControl->nMinimumTotalFee;
}
@@ -2389,51 +2647,117 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
return false;
}
- if (nFeeRet >= nFeeNeeded)
+ 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.
+ if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {
+ CAmount extraFeePaid = nFeeRet - nFeeNeeded;
+ std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
+ change_position->nValue += extraFeePaid;
+ nFeeRet -= extraFeePaid;
+ }
break; // Done, enough fee included.
+ }
+
+ // Try to reduce change to include necessary fee
+ if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {
+ CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet;
+ 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;
+ nFeeRet += additionalFeeNeeded;
+ break; // Done, able to increase fee from change
+ }
+ }
// Include more fee and try again.
nFeeRet = nFeeNeeded;
continue;
}
}
+
+ if (sign)
+ {
+ CTransaction txNewConst(txNew);
+ int nIn = 0;
+ for (const auto& coin : setCoins)
+ {
+ const CScript& scriptPubKey = coin.txout.scriptPubKey;
+ SignatureData sigdata;
+
+ if (!ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.txout.nValue, SIGHASH_ALL), scriptPubKey, sigdata))
+ {
+ strFailReason = _("Signing transaction failed");
+ return false;
+ } else {
+ UpdateTransaction(txNew, nIn, sigdata);
+ }
+
+ nIn++;
+ }
+ }
+
+ // Embed the constructed transaction data in wtxNew.
+ wtxNew.SetTx(MakeTransactionRef(std::move(txNew)));
+
+ // Limit size
+ if (GetTransactionWeight(wtxNew) >= MAX_STANDARD_TX_WEIGHT)
+ {
+ strFailReason = _("Transaction too large");
+ return false;
+ }
}
+ if (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, 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;
+ std::string errString;
+ if (!mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
+ strFailReason = _("Transaction has too long of a mempool chain");
+ return false;
+ }
+ }
return true;
}
/**
* Call after CreateTransaction unless you want to abort
*/
-bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
+bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state)
{
{
LOCK2(cs_main, cs_wallet);
- LogPrintf("CommitTransaction:\n%s", wtxNew.ToString());
+ LogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString());
{
- // This is only to keep the database open to defeat the auto-flush for the
- // duration of this scope. This is the only place where this optimization
- // maybe makes sense; please don't do it anywhere else.
- CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r+") : NULL;
-
// Take key pair from key pool so it won't be used again
reservekey.KeepKey();
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
- AddToWallet(wtxNew, false, pwalletdb);
+ AddToWallet(wtxNew);
// Notify that old coins are spent
- set<CWalletTx*> setCoins;
- BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
+ BOOST_FOREACH(const CTxIn& txin, wtxNew.tx->vin)
{
CWalletTx &coin = mapWallet[txin.prevout.hash];
coin.BindWallet(this);
NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
}
-
- if (fFileBacked)
- delete pwalletdb;
}
// Track how many getdata requests our transaction gets
@@ -2442,26 +2766,37 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
if (fBroadcastTransactions)
{
// Broadcast
- if (!wtxNew.AcceptToMemoryPool(false, maxTxFee))
- {
- // This must not fail. The transaction has already been signed and recorded.
- LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
- return false;
+ if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) {
+ LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason());
+ // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
+ } else {
+ wtxNew.RelayWalletTransaction(connman);
}
- wtxNew.RelayWalletTransaction();
}
}
return true;
}
-bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pwalletdb)
+void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) {
+ CWalletDB walletdb(*dbw);
+ return walletdb.ListAccountCreditDebit(strAccount, entries);
+}
+
+bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry)
+{
+ CWalletDB walletdb(*dbw);
+
+ return AddAccountingEntry(acentry, &walletdb);
+}
+
+bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwalletdb)
{
- if (!pwalletdb.WriteAccountingEntry_Backend(acentry))
+ if (!pwalletdb->WriteAccountingEntry_Backend(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((CWalletTx*)0, &entry)));
return true;
}
@@ -2471,14 +2806,14 @@ 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)
+CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, bool ignoreUserSetFee)
{
- // payTxFee is user-set "I want to pay this much"
+ // payTxFee is the user-set global for desired feerate
CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
// User didn't set: use -txconfirmtarget to estimate...
- if (nFeeNeeded == 0) {
+ if (nFeeNeeded == 0 || ignoreUserSetFee) {
int estimateFoundTarget = nConfirmTarget;
- nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes);
+ nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, &estimateFoundTarget, pool).GetFee(nTxBytes);
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
if (nFeeNeeded == 0)
nFeeNeeded = fallbackFee.GetFee(nTxBytes);
@@ -2496,13 +2831,11 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{
- if (!fFileBacked)
- return DB_LOAD_OK;
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();
@@ -2521,16 +2854,18 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
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
+ vchDefaultKey = CPubKey();
+ 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();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
@@ -2549,12 +2884,11 @@ 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);
+ vchDefaultKey = CPubKey();
+ 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();
@@ -2571,7 +2905,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;
{
@@ -2584,11 +2918,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(CBitcoinAddress(address).ToString(), strPurpose))
return false;
- return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName);
+ return CWalletDB(*dbw).WriteName(CBitcoinAddress(address).ToString(), strName);
}
bool CWallet::DelAddressBook(const CTxDestination& address)
@@ -2596,65 +2928,88 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
{
LOCK(cs_wallet); // mapAddressBook
- if(fFileBacked)
+ // Delete destdata tuples associated with address
+ std::string strAddress = CBitcoinAddress(address).ToString();
+ BOOST_FOREACH(const PAIRTYPE(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(CBitcoinAddress(address).ToString());
+ return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString());
}
-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;
+ }
}
+ // 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;
+}
+
+bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
+{
+ if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))
+ return false;
vchDefaultKey = vchPubKey;
return true;
}
/**
* 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);
+ CWalletDB walletdb(*dbw);
BOOST_FOREACH(int64_t nIndex, setKeyPool)
walletdb.ErasePool(nIndex);
setKeyPool.clear();
- if (IsLocked())
+ if (!TopUpKeyPool()) {
return false;
-
- 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);
}
- LogPrintf("CWallet::NewKeyPool wrote %d new keys\n", nKeys);
+ LogPrintf("CWallet::NewKeyPool rewrote keypool\n");
}
return true;
}
+size_t CWallet::KeypoolCountExternalKeys()
+{
+ AssertLockHeld(cs_wallet); // setKeyPool
+
+ // immediately return setKeyPool's size if HD or HD_SPLIT is disabled or not supported
+ if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT))
+ return setKeyPool.size();
+
+ CWalletDB walletdb(*dbw);
+
+ // count amount of external keys
+ size_t amountE = 0;
+ for(const int64_t& id : setKeyPool)
+ {
+ CKeyPool tmpKeypool;
+ if (!walletdb.ReadPool(id, tmpKeypool))
+ throw std::runtime_error(std::string(__func__) + ": read failed");
+ amountE += !tmpKeypool.fInternal;
+ }
+
+ return amountE;
+}
+
bool CWallet::TopUpKeyPool(unsigned int kpSize)
{
{
@@ -2663,30 +3018,44 @@ 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(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 amountExternal = KeypoolCountExternalKeys();
+ int64_t amountInternal = setKeyPool.size() - amountExternal;
+ int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - amountExternal, (int64_t) 0);
+ int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - amountInternal, (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 (i < missingInternal)
+ internal = true;
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
- if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
- throw runtime_error("TopUpKeyPool(): writing generated key failed");
+ if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey(internal), internal)))
+ throw std::runtime_error(std::string(__func__) + ": writing generated key failed");
setKeyPool.insert(nEnd);
- LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
+ LogPrintf("keypool added key %d, size=%u, internal=%d\n", nEnd, setKeyPool.size(), internal);
}
}
return true;
}
-void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
+void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool internal)
{
nIndex = -1;
keypool.vchPubKey = CPubKey();
@@ -2700,27 +3069,34 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
if(setKeyPool.empty())
return;
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
- nIndex = *(setKeyPool.begin());
- setKeyPool.erase(setKeyPool.begin());
- if (!walletdb.ReadPool(nIndex, keypool))
- throw runtime_error("ReserveKeyFromKeyPool(): read failed");
- if (!HaveKey(keypool.vchPubKey.GetID()))
- throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool");
- assert(keypool.vchPubKey.IsValid());
- LogPrintf("keypool reserve %d\n", nIndex);
+ // try to find a key that matches the internal/external filter
+ for(const int64_t& id : setKeyPool)
+ {
+ CKeyPool tmpKeypool;
+ if (!walletdb.ReadPool(id, tmpKeypool))
+ throw std::runtime_error(std::string(__func__) + ": read failed");
+ if (!HaveKey(tmpKeypool.vchPubKey.GetID()))
+ throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
+ if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT) || tmpKeypool.fInternal == internal)
+ {
+ nIndex = id;
+ keypool = tmpKeypool;
+ setKeyPool.erase(id);
+ assert(keypool.vchPubKey.IsValid());
+ LogPrintf("keypool reserve %d\n", nIndex);
+ return;
+ }
+ }
}
}
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);
}
@@ -2734,17 +3110,17 @@ void CWallet::ReturnKey(int64_t 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);
+ ReserveKeyFromKeyPool(nIndex, keypool, internal);
if (nIndex == -1)
{
if (IsLocked()) return false;
- result = GenerateNewKey();
+ result = GenerateNewKey(internal);
return true;
}
KeepKey(nIndex);
@@ -2761,19 +3137,43 @@ int64_t CWallet::GetOldestKeyPoolTime()
if (setKeyPool.empty())
return GetTime();
- // load oldest key from keypool, get time and return
CKeyPool keypool;
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
+
+ if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT))
+ {
+ // if HD & HD Chain Split is enabled, response max(oldest-internal-key, oldest-external-key)
+ int64_t now = GetTime();
+ int64_t oldest_external = now, oldest_internal = now;
+
+ for(const int64_t& id : setKeyPool)
+ {
+ if (!walletdb.ReadPool(id, keypool)) {
+ throw std::runtime_error(std::string(__func__) + ": read failed");
+ }
+ if (keypool.fInternal && keypool.nTime < oldest_internal) {
+ oldest_internal = keypool.nTime;
+ }
+ else if (!keypool.fInternal && keypool.nTime < oldest_external) {
+ oldest_external = keypool.nTime;
+ }
+ if (oldest_internal != now && oldest_external != now) {
+ break;
+ }
+ }
+ return std::max(oldest_internal, oldest_external);
+ }
+ // load oldest key from keypool, get time and return
int64_t nIndex = *(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
- throw runtime_error("GetOldestKeyPoolTime(): read oldest key in keypool failed");
+ throw std::runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
assert(keypool.vchPubKey.IsValid());
return keypool.nTime;
}
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
- map<CTxDestination, CAmount> balances;
+ std::map<CTxDestination, CAmount> balances;
{
LOCK(cs_wallet);
@@ -2781,7 +3181,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
CWalletTx *pcoin = &walletEntry.second;
- if (!CheckFinalTx(*pcoin) || !pcoin->IsTrusted())
+ if (!pcoin->IsTrusted())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
@@ -2791,15 +3191,15 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
continue;
- for (unsigned int i = 0; i < pcoin->vout.size(); i++)
+ for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++)
{
CTxDestination addr;
- if (!IsMine(pcoin->vout[i]))
+ if (!IsMine(pcoin->tx->vout[i]))
continue;
- if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr))
+ if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr))
continue;
- CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->vout[i].nValue;
+ CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue;
if (!balances.count(addr))
balances[addr] = 0;
@@ -2811,26 +3211,26 @@ 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)
{
CWalletTx *pcoin = &walletEntry.second;
- if (pcoin->vin.size() > 0)
+ if (pcoin->tx->vin.size() > 0)
{
bool any_mine = false;
// group all input addresses with each other
- BOOST_FOREACH(CTxIn txin, pcoin->vin)
+ BOOST_FOREACH(CTxIn txin, pcoin->tx->vin)
{
CTxDestination address;
if(!IsMine(txin)) /* If this input isn't mine, ignore it */
continue;
- if(!ExtractDestination(mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
+ if(!ExtractDestination(mapWallet[txin.prevout.hash].tx->vout[txin.prevout.n].scriptPubKey, address))
continue;
grouping.insert(address);
any_mine = true;
@@ -2839,7 +3239,7 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
// group change with input addresses
if (any_mine)
{
- BOOST_FOREACH(CTxOut txout, pcoin->vout)
+ BOOST_FOREACH(CTxOut txout, pcoin->tx->vout)
if (IsChange(txout))
{
CTxDestination txoutAddr;
@@ -2856,11 +3256,11 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
}
// group lone addrs by themselves
- for (unsigned int i = 0; i < pcoin->vout.size(); i++)
- if (IsMine(pcoin->vout[i]))
+ for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++)
+ if (IsMine(pcoin->tx->vout[i]))
{
CTxDestination address;
- if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address))
+ if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, address))
continue;
grouping.insert(address);
groupings.insert(grouping);
@@ -2868,20 +3268,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
+ BOOST_FOREACH(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;
+ BOOST_FOREACH(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);
+ BOOST_FOREACH(std::set<CTxDestination>* hit, hits)
{
merged->insert(hit->begin(), hit->end());
uniqueGroupings.erase(hit);
@@ -2894,8 +3294,8 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
setmap[element] = merged;
}
- set< set<CTxDestination> > ret;
- BOOST_FOREACH(set<CTxDestination>* uniqueGrouping, uniqueGroupings)
+ std::set< std::set<CTxDestination> > ret;
+ BOOST_FOREACH(std::set<CTxDestination>* uniqueGrouping, uniqueGroupings)
{
ret.insert(*uniqueGrouping);
delete uniqueGrouping;
@@ -2904,57 +3304,26 @@ 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;
+ std::set<CTxDestination> result;
BOOST_FOREACH(const PAIRTYPE(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 {
@@ -2982,40 +3351,29 @@ void CReserveKey::ReturnKey()
vchPubKey = CPubKey();
}
-void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
+void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
{
setAddress.clear();
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
LOCK2(cs_main, cs_wallet);
BOOST_FOREACH(const int64_t& id, setKeyPool)
{
CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool))
- throw runtime_error("GetAllReserveKeyHashes(): read failed");
+ throw std::runtime_error(std::string(__func__) + ": read failed");
assert(keypool.vchPubKey.IsValid());
CKeyID keyID = keypool.vchPubKey.GetID();
if (!HaveKey(keyID))
- throw runtime_error("GetAllReserveKeyHashes(): unknown key in key pool");
+ throw std::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);
- }
-}
-
-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;
@@ -3094,17 +3452,19 @@ public:
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 reorganised; use a 144-block safety margin
+ 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);
@@ -3127,7 +3487,7 @@ 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.vout) {
+ BOOST_FOREACH(const CTxOut &txout, wtx.tx->vout) {
// iterate over all their outputs
CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
BOOST_FOREACH(const CKeyID &keyid, vAffected) {
@@ -3143,7 +3503,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)
@@ -3152,18 +3577,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(CBitcoinAddress(dest).ToString(), 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(CBitcoinAddress(dest).ToString(), key);
}
bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
@@ -3201,11 +3622,10 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
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));
@@ -3220,25 +3640,26 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
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 CWallet::InitLoadWallet()
+CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
{
- std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
-
// needed to restore wallet transaction meta data after -zapwallettxes
std::vector<CWalletTx> vWtx;
if (GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
- CWallet *tempWallet = new CWallet(walletFile);
+ std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));
+ CWallet *tempWallet = new CWallet(std::move(dbw));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
- return InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
+ InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
+ return NULL;
}
delete tempWallet;
@@ -3249,27 +3670,34 @@ bool CWallet::InitLoadWallet()
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)
- return InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
+ if (nLoadWalletRet == DB_CORRUPT) {
+ InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
+ return NULL;
+ }
else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
{
InitWarning(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect."),
walletFile));
}
- else if (nLoadWalletRet == DB_TOO_NEW)
- return InitError(strprintf(_("Error loading %s: Wallet requires newer version of %s"),
- walletFile, _(PACKAGE_NAME)));
+ else if (nLoadWalletRet == DB_TOO_NEW) {
+ InitError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, _(PACKAGE_NAME)));
+ return NULL;
+ }
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
- return InitError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)));
+ InitError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)));
+ return NULL;
+ }
+ else {
+ InitError(strprintf(_("Error loading %s"), walletFile));
+ return NULL;
}
- else
- return InitError(strprintf(_("Error loading %s"), walletFile));
}
if (GetBoolArg("-upgradewallet", fFirstRun))
@@ -3285,7 +3713,8 @@ bool CWallet::InitLoadWallet()
LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
if (nMaxVersion < walletInstance->GetVersion())
{
- return InitError(_("Cannot downgrade wallet"));
+ InitError(_("Cannot downgrade wallet"));
+ return NULL;
}
walletInstance->SetMaxVersion(nMaxVersion);
}
@@ -3293,45 +3722,50 @@ bool CWallet::InitLoadWallet()
if (fFirstRun)
{
// Create new keyUser and set as default key
- if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && walletInstance->hdChain.masterKeyID.IsNull()) {
+ if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && !walletInstance->IsHDEnabled()) {
+
+ // ensure this wallet.dat can only be opened by clients supporting HD with chain split
+ walletInstance->SetMinVersion(FEATURE_HD_SPLIT);
+
// generate a new master key
- CKey key;
- key.MakeNewKey(true);
- if (!walletInstance->SetHDMasterKey(key))
- throw std::runtime_error("CWallet::GenerateNewKey(): Storing master key failed");
+ 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)) {
+ if (walletInstance->GetKeyFromPool(newDefaultKey, false)) {
walletInstance->SetDefaultKey(newDefaultKey);
- if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive"))
- return InitError(_("Cannot write default address") += "\n");
+ if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) {
+ InitError(_("Cannot write default address") += "\n");
+ return NULL;
+ }
}
walletInstance->SetBestChain(chainActive.GetLocator());
}
- else if (mapArgs.count("-usehd")) {
+ else if (IsArgSet("-usehd")) {
bool useHD = GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET);
- if (!walletInstance->hdChain.masterKeyID.IsNull() && !useHD)
- return InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
- if (walletInstance->hdChain.masterKeyID.IsNull() && useHD)
- return InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile));
+ if (walletInstance->IsHDEnabled() && !useHD) {
+ InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
+ return NULL;
+ }
+ if (!walletInstance->IsHDEnabled() && useHD) {
+ InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile));
+ return NULL;
+ }
}
LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
RegisterValidationInterface(walletInstance);
- CBlockIndex *pindexRescan = chainActive.Tip();
- if (GetBoolArg("-rescan", false))
- pindexRescan = chainActive.Genesis();
- else
+ CBlockIndex *pindexRescan = chainActive.Genesis();
+ if (!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)
{
@@ -3344,8 +3778,10 @@ bool CWallet::InitLoadWallet()
while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
block = block->pprev;
- if (pindexRescan != block)
- return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
+ 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;
+ }
}
uiInterface.InitMessage(_("Rescanning..."));
@@ -3354,12 +3790,12 @@ bool CWallet::InitLoadWallet()
walletInstance->ScanForWalletTransactions(pindexRescan, true);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator());
- nWalletDBUpdated++;
+ CWalletDB::IncrementUpdateCounter();
// Restore wallet transaction metadata after -zapwallettxes=1
if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
{
- CWalletDB walletdb(walletFile);
+ CWalletDB walletdb(*walletInstance->dbw);
BOOST_FOREACH(const CWalletTx& wtxOld, vWtx)
{
@@ -3383,113 +3819,156 @@ bool CWallet::InitLoadWallet()
}
walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
- pwalletMain = walletInstance;
+ {
+ LOCK(walletInstance->cs_wallet);
+ LogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
+ LogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size());
+ LogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size());
+ }
+
+ return walletInstance;
+}
+
+bool CWallet::InitLoadWallet()
+{
+ if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ pwalletMain = NULL;
+ LogPrintf("Wallet disabled!\n");
+ return true;
+ }
+
+ std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
+
+ if (boost::filesystem::path(walletFile).filename() != walletFile) {
+ return InitError(_("-wallet parameter must only specify a filename (not a path)"));
+ } else if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) {
+ return InitError(_("Invalid characters in -wallet filename"));
+ }
+
+ CWallet * const pwallet = CreateWalletFromFile(walletFile);
+ if (!pwallet) {
+ return false;
+ }
+ pwalletMain = pwallet;
+
return true;
}
+std::atomic<bool> CWallet::fFlushScheduled(false);
+
+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::fFlushScheduled.exchange(true)) {
+ scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
+ }
+}
+
bool CWallet::ParameterInteraction()
{
- if (mapArgs.count("-mintxfee"))
+ 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(mapArgs["-mintxfee"], n) && n > 0)
- CWallet::minTxFee = CFeeRate(n);
- else
- return InitError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"]));
+ 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 (mapArgs.count("-fallbackfee"))
+ if (IsArgSet("-fallbackfee"))
{
CAmount nFeePerK = 0;
- if (!ParseMoney(mapArgs["-fallbackfee"], nFeePerK))
- return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), mapArgs["-fallbackfee"]));
+ if (!ParseMoney(GetArg("-fallbackfee", ""), nFeePerK))
+ return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), GetArg("-fallbackfee", "")));
if (nFeePerK > HIGH_TX_FEE_PER_KB)
- InitWarning(_("-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available."));
+ InitWarning(AmountHighWarn("-fallbackfee") + " " +
+ _("This is the transaction fee you may pay when fee estimates are not available."));
CWallet::fallbackFee = CFeeRate(nFeePerK);
}
- if (mapArgs.count("-paytxfee"))
+ if (IsArgSet("-paytxfee"))
{
CAmount nFeePerK = 0;
- if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK))
- return InitError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"]));
+ if (!ParseMoney(GetArg("-paytxfee", ""), nFeePerK))
+ return InitError(AmountErrMsg("paytxfee", GetArg("-paytxfee", "")));
if (nFeePerK > HIGH_TX_FEE_PER_KB)
- InitWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
+ 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)"),
- mapArgs["-paytxfee"], ::minRelayTxFee.ToString()));
+ GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
}
}
- if (mapArgs.count("-maxtxfee"))
+ if (IsArgSet("-maxtxfee"))
{
CAmount nMaxFee = 0;
- if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee))
- return InitError(AmountErrMsg("maxtxfee", mapArgs["-maxtxfee"]));
+ 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)"),
- mapArgs["-maxtxfee"], ::minRelayTxFee.ToString()));
+ 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);
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)
@@ -3498,34 +3977,13 @@ CWalletKey::CWalletKey(int64_t nExpires)
nTimeExpires = nExpires;
}
-int CMerkleTx::SetMerkleBranch(const CBlock& block)
+void CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
{
- AssertLockHeld(cs_main);
- CBlock blockTmp;
-
// Update the tx's hashBlock
- hashBlock = block.GetHash();
-
- // Locate the transaction
- for (nIndex = 0; nIndex < (int)block.vtx.size(); nIndex++)
- if (block.vtx[nIndex] == *(CTransaction*)this)
- break;
- if (nIndex == (int)block.vtx.size())
- {
- nIndex = -1;
- LogPrintf("ERROR: SetMerkleBranch(): couldn't find tx in block\n");
- return 0;
- }
-
- // Is the tx in a block that's in the main chain
- BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
- if (mi == mapBlockIndex.end())
- return 0;
- const CBlockIndex* pindex = (*mi).second;
- if (!pindex || !chainActive.Contains(pindex))
- return 0;
+ hashBlock = pindex->GetBlockHash();
- return chainActive.Height() - pindex->nHeight + 1;
+ // set the position of the transaction in the block
+ nIndex = posInBlock;
}
int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
@@ -3551,12 +4009,11 @@ 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(bool fLimitFree, CAmount nAbsurdFee)
+bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
{
- CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee);
+ return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, NULL, false, nAbsurdFee);
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index e9d669a7d1..69f51b3f64 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -7,17 +7,20 @@
#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"
#include <algorithm>
+#include <atomic>
#include <map>
#include <set>
#include <stdexcept>
@@ -26,8 +29,6 @@
#include <utility>
#include <vector>
-#include <boost/shared_ptr.hpp>
-
extern CWallet* pwalletMain;
/**
@@ -36,7 +37,7 @@ 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;
//! -paytxfee default
@@ -45,18 +46,22 @@ static const CAmount DEFAULT_TRANSACTION_FEE = 0;
static const CAmount DEFAULT_FALLBACK_FEE = 20000;
//! -mintxfee default
static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000;
-//! minimum change amount
+//! 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 = 2;
-//! Largest (in bytes) free transaction we're willing to create
-static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
+static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
+//! -walletrbf default
+static const bool DEFAULT_WALLET_RBF = false;
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;
@@ -67,7 +72,9 @@ class CCoinControl;
class COutput;
class CReserveKey;
class CScript;
+class CScheduler;
class CTxMemPool;
+class CBlockPolicyEstimator;
class CWalletTx;
/** (client) version numbers for particular wallet features */
@@ -78,7 +85,11 @@ enum WalletFeature
FEATURE_WALLETCRYPT = 40000, // wallet encryption
FEATURE_COMPRPUBKEY = 60000, // compressed public keys
- FEATURE_LATEST = 60000
+ 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_LATEST = FEATURE_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY as latest version
};
@@ -88,18 +99,33 @@ 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;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ int nVersion = s.GetVersion();
+ if (!(s.GetType() & SER_GETHASH))
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);
+ }
}
};
@@ -129,7 +155,7 @@ struct CRecipient
typedef std::map<std::string, std::string> mapValue_t;
-static void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
+static inline void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
{
if (!mapValue.count("n"))
{
@@ -140,7 +166,7 @@ static void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
}
-static void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
+static inline void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
{
if (nOrderPos == -1)
return;
@@ -155,13 +181,14 @@ struct COutputEntry
};
/** A transaction with a merkle branch linking it to the block chain. */
-class CMerkleTx : public CTransaction
+class CMerkleTx
{
private:
/** Constant used in hashBlock to indicate tx has been abandoned */
static const uint256 ABANDON_HASH;
public:
+ CTransactionRef tx;
uint256 hashBlock;
/* An nIndex == -1 means that hashBlock (in nonzero) refers to the earliest
@@ -173,33 +200,43 @@ public:
CMerkleTx()
{
+ SetTx(MakeTransactionRef());
Init();
}
- CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
+ CMerkleTx(CTransactionRef arg)
{
+ SetTx(std::move(arg));
Init();
}
+ /** Helper conversion operator to allow passing CMerkleTx where CTransaction is expected.
+ * TODO: adapt callers and remove this operator. */
+ operator const CTransaction&() const { return *tx; }
+
void Init()
{
hashBlock = uint256();
nIndex = -1;
}
+ void SetTx(CTransactionRef arg)
+ {
+ tx = std::move(arg);
+ }
+
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
std::vector<uint256> vMerkleBranch; // For compatibility with older versions.
- READWRITE(*(CTransaction*)this);
- nVersion = this->nVersion;
+ READWRITE(tx);
READWRITE(hashBlock);
READWRITE(vMerkleBranch);
READWRITE(nIndex);
}
- int SetMerkleBranch(const CBlock& block);
+ void SetMerkleBranch(const CBlockIndex* pIndex, int posInBlock);
/**
* Return depth of transaction in blockchain:
@@ -212,10 +249,13 @@ public:
bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; }
int GetBlocksToMaturity() const;
/** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
- bool AcceptToMemoryPool(bool fLimitFree, const CAmount nAbsurdFee);
+ bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state);
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
+
+ const uint256& GetHash() const { return tx->GetHash(); }
+ bool IsCoinBase() const { return tx->IsCoinBase(); }
};
/**
@@ -228,11 +268,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
@@ -262,17 +341,7 @@ public:
Init(NULL);
}
- CWalletTx(const CWallet* pwalletIn)
- {
- Init(pwalletIn);
- }
-
- CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
- {
- Init(pwalletIn);
- }
-
- CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
+ CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) : CMerkleTx(std::move(arg))
{
Init(pwalletIn);
}
@@ -311,7 +380,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
if (ser_action.ForRead())
Init(NULL);
char fSpent = false;
@@ -346,7 +415,6 @@ public:
}
mapValue.erase("fromaccount");
- mapValue.erase("version");
mapValue.erase("spent");
mapValue.erase("n");
mapValue.erase("timesmart");
@@ -357,6 +425,7 @@ public:
{
fCreditCached = false;
fAvailableCreditCached = false;
+ fImmatureCreditCached = false;
fWatchDebitCached = false;
fWatchCreditCached = false;
fAvailableWatchCreditCached = false;
@@ -383,9 +452,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);
@@ -400,13 +466,40 @@ public:
int64_t GetTxTime() const;
int GetRequestCount() const;
- bool RelayWalletTransaction();
+ 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
{
@@ -414,12 +507,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;
@@ -444,8 +548,9 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ int nVersion = s.GetVersion();
+ if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vchPrivKey);
READWRITE(nTimeCreated);
@@ -489,8 +594,9 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ int nVersion = s.GetVersion();
+ if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
//! Note: strAccount is serialized as part of the key, not here.
READWRITE(nCreditDebit);
@@ -503,7 +609,7 @@ public:
if (!(mapValue.empty() && _ssExtra.empty()))
{
- CDataStream ss(nType, nVersion);
+ CDataStream ss(s.GetType(), s.GetVersion());
ss.insert(ss.begin(), '\0');
ss << mapValue;
ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
@@ -519,7 +625,7 @@ public:
mapValue.clear();
if (std::string::npos != nSepPos)
{
- CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion);
+ CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), s.GetType(), s.GetVersion());
ss >> mapValue;
_ssExtra = std::vector<char>(ss.begin(), ss.end());
}
@@ -543,12 +649,16 @@ private:
class CWallet : public CCryptoKeyStore, public CValidationInterface
{
private:
+ 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 = NULL) const;
CWalletDB *pwalletdbEncryption;
@@ -577,40 +687,89 @@ 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 = NULL, int posInBlock = 0);
+
/* the HD chain data model (external chain counters) */
CHDChain hdChain;
+ /* HD derive new child key (on internal or external chain) */
+ void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool internal = false);
+
+ std::set<int64_t> setKeyPool;
+
+ 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;
+
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;
- bool fFileBacked;
- std::string strWalletFile;
+ /** Get database handle used by this wallet. Ideally this function would
+ * not be necessary.
+ */
+ CWalletDBWrapper& GetDBHandle()
+ {
+ return *dbw;
+ }
+
+ /** Get a name for this wallet for logging/debugging purposes.
+ */
+ std::string GetName() const
+ {
+ if (dbw) {
+ return dbw->GetName();
+ } else {
+ return "dummy";
+ }
+ }
- std::set<int64_t> setKeyPool;
- std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
+ void LoadKeyPool(int nIndex, const CKeyPool &keypool)
+ {
+ setKeyPool.insert(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);
+ }
+
+ // 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)
+ // Create wallet with passed-in database handle
+ CWallet(std::unique_ptr<CWalletDBWrapper> dbw_in) : dbw(std::move(dbw_in))
{
SetNull();
-
- strWalletFile = strWalletFileIn;
- fFileBacked = true;
}
~CWallet()
@@ -623,7 +782,6 @@ public:
{
nWalletVersion = FEATURE_BASE;
nWalletMaxVersion = FEATURE_BASE;
- fFileBacked = false;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
nOrderPosNext = 0;
@@ -631,6 +789,9 @@ public:
nLastResend = 0;
nTimeFirstKey = 0;
fBroadcastTransactions = false;
+ nRelockTime = 0;
+ fAbortRescan = false;
+ fScanningWallet = false;
}
std::map<uint256, CWalletTx> mapWallet;
@@ -649,8 +810,6 @@ public:
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
@@ -659,7 +818,7 @@ public:
/**
* 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 = NULL, 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;
/**
* Shuffle and select coins until nTargetValue is reached while avoiding
@@ -667,7 +826,7 @@ public:
* completion the coin set and corresponding actual target value is
* assembled
*/
- bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, 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;
@@ -677,25 +836,33 @@ public:
void UnlockAllCoins();
void ListLockedCoins(std::vector<COutPoint>& vOutpts);
+ /*
+ * Rescan abort properties
+ */
+ void AbortRescan() { fAbortRescan = true; }
+ bool IsAbortingRescan() { return fAbortRescan; }
+ bool IsScanning() { return fScanningWallet; }
+
/**
* keystore implementation
* Generate a new key
*/
- CPubKey GenerateNewKey();
+ CPubKey GenerateNewKey(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;
//! 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
@@ -708,45 +875,55 @@ public:
bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) 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);
+ 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);
void MarkDirty();
- bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
- void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock);
- bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
- int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
+ bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
+ bool LoadToWallet(const CWalletTx& wtxIn);
+ 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);
+ CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
- void ResendWalletTransactions(int64_t nBestBlockTime);
- std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime);
+ void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
+ std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);
CAmount GetBalance() const;
CAmount GetUnconfirmedBalance() const;
CAmount GetImmatureBalance() const;
CAmount GetWatchOnlyBalance() const;
CAmount GetUnconfirmedWatchOnlyBalance() const;
CAmount GetImmatureWatchOnlyBalance() const;
+ CAmount GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) 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 CTxDestination& destChange = CNoDestination());
+ 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, bool keepReserveKey = true, const CTxDestination& destChange = CNoDestination());
+ bool SignTransaction(CMutableTransaction& tx);
/**
* Create a new transaction paying the recipients with a set of coins
@@ -755,9 +932,13 @@ public:
*/
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);
- bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
+ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state);
- bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb);
+ 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;
@@ -765,7 +946,7 @@ public:
* Estimate the minimum fee considering user set parameters
* and the required fee
*/
- static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool);
+ static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, bool ignoreUserSetFee = false);
/**
* Return the minimum required fee taking into account the
* floating relay fee and user set minimum transaction fee
@@ -773,22 +954,25 @@ public:
static CAmount GetRequiredFee(unsigned int nTxBytes);
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 internal);
void KeepKey(int64_t nIndex);
void ReturnKey(int64_t nIndex);
- bool GetKeyFromPool(CPubKey &key);
+ bool GetKeyFromPool(CPubKey &key, bool internal = false);
int64_t GetOldestKeyPoolTime();
void GetAllReserveKeys(std::set<CKeyID>& setAddress) const;
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;
@@ -798,9 +982,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);
@@ -810,9 +996,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);
@@ -822,12 +1008,7 @@ 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) override;
unsigned int GetKeyPoolSize()
{
@@ -849,6 +1030,9 @@ 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);
@@ -885,12 +1069,22 @@ public:
/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
bool AbandonTransaction(const uint256& hashTx);
+ /** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
+ bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
+
/* Returns the wallets help message */
static std::string GetWalletHelpString(bool showDebug);
/* 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(CScheduler& scheduler);
+
/* Wallets parameter interaction */
static bool ParameterInteraction();
@@ -898,10 +1092,19 @@ public:
/* Set the HD chain model (chain child index counters) */
bool SetHDChain(const CHDChain& chain, bool memonly);
+ const CHDChain& GetHDChain() const { return hdChain; }
- /* Set the current HD master key (will reset the chain child index counters) */
- bool SetHDMasterKey(const CKey& key);
- const CHDChain& GetHDChain() { return hdChain; }
+ /* Returns true if HD is enabled */
+ 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)
+ 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. */
@@ -918,13 +1121,17 @@ public:
pwallet = pwalletIn;
}
+ 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(); }
};
@@ -952,11 +1159,36 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ int nVersion = s.GetVersion();
+ if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vchPubKey);
}
};
+// 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 72af8ab7b2..a90fa6dbbd 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -7,7 +7,8 @@
#include "base58.h"
#include "consensus/validation.h"
-#include "main.h" // For CheckTransaction
+#include "fs.h"
+#include "validation.h" // For CheckTransaction
#include "protocol.h"
#include "serialize.h"
#include "sync.h"
@@ -15,63 +16,63 @@
#include "utiltime.h"
#include "wallet/wallet.h"
+#include <atomic>
+
#include <boost/version.hpp>
-#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
-#include <boost/scoped_ptr.hpp>
#include <boost/thread.hpp>
-using namespace std;
-
static uint64_t nAccountingEntryNumber = 0;
+static std::atomic<unsigned int> nWalletDBUpdateCounter;
+
//
// 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);
+ nWalletDBUpdateCounter++;
+ return batch.Write(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));
+ nWalletDBUpdateCounter++;
+ return batch.Erase(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);
+ nWalletDBUpdateCounter++;
+ return batch.Write(std::make_pair(std::string("purpose"), strAddress), strPurpose);
}
-bool CWalletDB::ErasePurpose(const string& strPurpose)
+bool CWalletDB::ErasePurpose(const std::string& strPurpose)
{
- nWalletDBUpdated++;
- return Erase(make_pair(string("purpose"), strPurpose));
+ nWalletDBUpdateCounter++;
+ return batch.Erase(std::make_pair(std::string("purpose"), strPurpose));
}
bool CWalletDB::WriteTx(const CWalletTx& wtx)
{
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
+ nWalletDBUpdateCounter++;
+ return batch.Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
}
bool CWalletDB::EraseTx(uint256 hash)
{
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("tx"), hash));
+ nWalletDBUpdateCounter++;
+ return batch.Erase(std::make_pair(std::string("tx"), hash));
}
bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
{
- nWalletDBUpdated++;
+ nWalletDBUpdateCounter++;
- if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
+ if (!batch.Write(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta, false))
return false;
@@ -81,7 +82,7 @@ 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 batch.Write(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
}
bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
@@ -89,107 +90,111 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
const CKeyMetadata &keyMeta)
{
const bool fEraseUnencryptedKey = true;
- nWalletDBUpdated++;
+ nWalletDBUpdateCounter++;
- if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
+ if (!batch.Write(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta))
return false;
- if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
+ if (!batch.Write(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));
+ batch.Erase(std::make_pair(std::string("key"), vchPubKey));
+ batch.Erase(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);
+ nWalletDBUpdateCounter++;
+ return batch.Write(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);
+ nWalletDBUpdateCounter++;
+ return batch.Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&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');
+ nWalletDBUpdateCounter++;
+ if (!batch.Write(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)), keyMeta))
+ return false;
+ return batch.Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
}
bool CWalletDB::EraseWatchOnly(const CScript &dest)
{
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
+ nWalletDBUpdateCounter++;
+ if (!batch.Erase(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest))))
+ return false;
+ return batch.Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&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);
+ nWalletDBUpdateCounter++;
+ batch.Write(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
+ return batch.Write(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);
+ nWalletDBUpdateCounter++;
+ return batch.Write(std::string("orderposnext"), nOrderPosNext);
}
bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
{
- nWalletDBUpdated++;
- return Write(std::string("defaultkey"), vchPubKey);
+ nWalletDBUpdateCounter++;
+ return batch.Write(std::string("defaultkey"), vchPubKey);
}
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);
+ nWalletDBUpdateCounter++;
+ return batch.Write(std::make_pair(std::string("pool"), nPool), keypool);
}
bool CWalletDB::ErasePool(int64_t nPool)
{
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("pool"), nPool));
+ nWalletDBUpdateCounter++;
+ return batch.Erase(std::make_pair(std::string("pool"), nPool));
}
bool CWalletDB::WriteMinVersion(int nVersion)
{
- return Write(std::string("minversion"), nVersion);
+ return batch.Write(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 batch.Write(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 batch.Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
}
bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry)
@@ -197,9 +202,9 @@ bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry)
return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
}
-CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount)
+CAmount CWalletDB::GetAccountCreditDebit(const std::string& strAccount)
{
- list<CAccountingEntry> entries;
+ std::list<CAccountingEntry> entries;
ListAccountCreditDebit(strAccount, entries);
CAmount nCreditDebit = 0;
@@ -209,33 +214,33 @@ CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount)
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("CWalletDB::ListAccountCreditDebit(): cannot create DB cursor");
- unsigned int fFlags = DB_SET_RANGE;
+ 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 (fFlags == DB_SET_RANGE)
- ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0)));
+ if (setRange)
+ 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, fFlags);
- fFlags = DB_NEXT;
+ int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange);
+ setRange = false;
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
{
pcursor->close();
- throw runtime_error("CWalletDB::ListAccountCreditDebit(): 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;
@@ -252,94 +257,19 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
pcursor->close();
}
-DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet)
-{
- LOCK(pwallet->cs_wallet);
- // 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;
- TxItems txByTime;
-
- for (map<uint256, CWalletTx>::iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it)
- {
- CWalletTx* wtx = &((*it).second);
- txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
- }
- list<CAccountingEntry> acentries;
- ListAccountCreditDebit("", acentries);
- BOOST_FOREACH(CAccountingEntry& entry, acentries)
- {
- txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
- }
-
- int64_t& nOrderPosNext = pwallet->nOrderPosNext;
- nOrderPosNext = 0;
- std::vector<int64_t> nOrderPosOffsets;
- for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
- {
- CWalletTx *const pwtx = (*it).second.first;
- CAccountingEntry *const pacentry = (*it).second.second;
- int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;
-
- if (nOrderPos == -1)
- {
- nOrderPos = nOrderPosNext++;
- nOrderPosOffsets.push_back(nOrderPos);
-
- if (pwtx)
- {
- if (!WriteTx(*pwtx))
- return DB_LOAD_FAIL;
- }
- else
- if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
- return DB_LOAD_FAIL;
- }
- else
- {
- int64_t nOrderPosOff = 0;
- BOOST_FOREACH(const int64_t& nOffsetStart, nOrderPosOffsets)
- {
- if (nOrderPos >= nOffsetStart)
- ++nOrderPosOff;
- }
- nOrderPos += nOrderPosOff;
- nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
-
- if (!nOrderPosOff)
- continue;
-
- // Since we're changing the order, write it back
- if (pwtx)
- {
- if (!WriteTx(*pwtx))
- return DB_LOAD_FAIL;
- }
- else
- if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
- return DB_LOAD_FAIL;
- }
- }
- WriteOrderPosNext(nOrderPosNext);
-
- return DB_LOAD_OK;
-}
-
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;
@@ -348,7 +278,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
@@ -357,13 +287,13 @@ 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;
}
else if (strType == "purpose")
{
- string strAddress;
+ std::string strAddress;
ssKey >> strAddress;
ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose;
}
@@ -400,11 +330,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
if (wtx.nOrderPos == -1)
wss.fAnyUnordered = true;
- pwallet->AddToWallet(wtx, true, NULL);
+ pwallet->LoadToWallet(wtx);
}
else if (strType == "acentry")
{
- string strAccount;
+ std::string strAccount;
ssKey >> strAccount;
uint64_t nNumber;
ssKey >> nNumber;
@@ -421,16 +351,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "watchs")
{
+ wss.nWatchKeys++;
CScript script;
ssKey >> *(CScriptBase*)(&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")
{
@@ -520,7 +447,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++;
@@ -531,20 +458,27 @@ 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 >> *(CScriptBase*)(&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")
{
@@ -556,14 +490,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> nIndex;
CKeyPool keypool;
ssValue >> keypool;
- pwallet->setKeyPool.insert(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 (pwallet->mapKeyMetadata.count(keyid) == 0)
- pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
+
+ pwallet->LoadKeyPool(nIndex, keypool);
}
else if (strType == "version")
{
@@ -616,7 +544,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");
@@ -629,10 +557,10 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
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;
@@ -640,7 +568,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
}
// Get cursor
- Dbc* pcursor = GetCursor();
+ Dbc* pcursor = batch.GetCursor();
if (!pcursor)
{
LogPrintf("Error getting wallet database cursor\n");
@@ -652,7 +580,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)
@@ -662,7 +590,7 @@ 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
@@ -704,8 +632,8 @@ 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)
WriteTx(pwallet->mapWallet[hash]);
@@ -718,7 +646,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
WriteVersion(CLIENT_VERSION);
if (wss.fAnyUnordered)
- result = ReorderTransactions(pwallet);
+ result = pwallet->ReorderTransactions();
pwallet->laccentries.clear();
ListAccountCreditDebit("*", pwallet->laccentries);
@@ -729,24 +657,21 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
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");
@@ -758,7 +683,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)
@@ -767,7 +692,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;
@@ -795,12 +720,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;
}
@@ -810,7 +735,7 @@ DBErrors CWalletDB::ZapSelectTx(CWallet* pwallet, vector<uint256>& vTxHashIn, ve
// erase each matching wallet TX
bool delerror = false;
- vector<uint256>::iterator it = vTxHashIn.begin();
+ std::vector<uint256>::iterator it = vTxHashIn.begin();
BOOST_FOREACH (uint256 hash, vTxHash) {
while (it < vTxHashIn.end() && (*it) < hash) {
it++;
@@ -819,9 +744,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);
@@ -834,11 +758,11 @@ 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;
@@ -851,172 +775,133 @@ DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
return DB_LOAD_OK;
}
-void ThreadFlushWalletDB(const string& strFile)
+void MaybeCompactWalletDB()
{
- // Make this thread recognisable as the wallet flushing thread
- RenameThread("bitcoin-wallet");
-
- static bool fOneThread;
- if (fOneThread)
+ static std::atomic<bool> fOneThread;
+ if (fOneThread.exchange(true)) {
return;
- fOneThread = true;
- if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET))
+ }
+ if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
return;
+ }
- unsigned int nLastSeen = nWalletDBUpdated;
- unsigned int nLastFlushed = nWalletDBUpdated;
- int64_t nLastWalletUpdate = GetTime();
- while (true)
- {
- MilliSleep(500);
-
- if (nLastSeen != nWalletDBUpdated)
- {
- nLastSeen = nWalletDBUpdated;
- nLastWalletUpdate = GetTime();
- }
+ static unsigned int nLastSeen = CWalletDB::GetUpdateCounter();
+ static unsigned int nLastFlushed = CWalletDB::GetUpdateCounter();
+ static int64_t nLastWalletUpdate = GetTime();
- 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 (nLastSeen != CWalletDB::GetUpdateCounter())
+ {
+ nLastSeen = CWalletDB::GetUpdateCounter();
+ nLastWalletUpdate = GetTime();
+ }
- if (nRefCount == 0)
- {
- boost::this_thread::interruption_point();
- 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 (nLastFlushed != CWalletDB::GetUpdateCounter() && GetTime() - nLastWalletUpdate >= 2)
+ {
+ if (CDB::PeriodicFlush(pwalletMain->GetDBHandle())) {
+ nLastFlushed = CWalletDB::GetUpdateCounter();
}
}
+ 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))
+{
+ return CDB::Recover(filename, callbackDataIn, recoverKVcallback);
+}
+
+bool CWalletDB::Recover(const std::string& filename)
+{
+ // recover without a key filter callback
+ // results in recovering all record types
+ return CWalletDB::Recover(filename, NULL, NULL);
+}
- std::vector<CDBEnv::KeyValPair> salvagedData;
- bool fSuccess = dbenv.Salvage(newFilename, true, salvagedData);
- if (salvagedData.empty())
+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());
-
- boost::scoped_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, errorStr, warningStr, 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);
+ nWalletDBUpdateCounter++;
+ return batch.Write(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)));
+ nWalletDBUpdateCounter++;
+ return batch.Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
}
bool CWalletDB::WriteHDChain(const CHDChain& chain)
{
- nWalletDBUpdated++;
- return Write(std::string("hdchain"), chain);
+ nWalletDBUpdateCounter++;
+ return batch.Write(std::string("hdchain"), chain);
+}
+
+void CWalletDB::IncrementUpdateCounter()
+{
+ nWalletDBUpdateCounter++;
+}
+
+unsigned int CWalletDB::GetUpdateCounter()
+{
+ return nWalletDBUpdateCounter;
+}
+
+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 5addd5c5c0..cd9fe279c5 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// 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.
@@ -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,26 +61,31 @@ 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(); }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
+ inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(this->nVersion);
- nVersion = 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();
}
};
@@ -94,9 +114,8 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(this->nVersion);
- nVersion = this->nVersion;
READWRITE(nCreateTime);
if (this->nVersion >= VERSION_WITH_HDDATA)
{
@@ -114,11 +133,16 @@ 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
{
public:
- CWalletDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose)
+ CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool _fFlushOnClose = true) :
+ batch(dbw, pszMode, _fFlushOnClose)
{
}
@@ -137,7 +161,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);
@@ -155,6 +179,7 @@ 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,24 +192,47 @@ public:
CAmount GetAccountCreditDebit(const std::string& strAccount);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
- DBErrors ReorderTransactions(CWallet* pwallet);
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));
+ /* Recover convenience-function to bypass the key filter callback, called when verify fails, recovers everything */
+ static bool Recover(const std::string& 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);
+ static void IncrementUpdateCounter();
+ static unsigned int GetUpdateCounter();
+
+ //! 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:
+ CDB batch;
+
CWalletDB(const CWalletDB&);
void operator=(const CWalletDB&);
-
- bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry);
};
-void ThreadFlushWalletDB(const std::string& strFile);
+//! 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
new file mode 100644
index 0000000000..2c1b1b0e12
--- /dev/null
+++ b/src/warnings.cpp
@@ -0,0 +1,89 @@
+// 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.
+
+#include "sync.h"
+#include "clientversion.h"
+#include "util.h"
+#include "warnings.h"
+
+CCriticalSection cs_warnings;
+std::string strMiscWarning;
+bool fLargeWorkForkFound = false;
+bool fLargeWorkInvalidChainFound = false;
+
+void SetMiscWarning(const std::string& strWarning)
+{
+ LOCK(cs_warnings);
+ strMiscWarning = strWarning;
+}
+
+void SetfLargeWorkForkFound(bool flag)
+{
+ LOCK(cs_warnings);
+ fLargeWorkForkFound = flag;
+}
+
+bool GetfLargeWorkForkFound()
+{
+ LOCK(cs_warnings);
+ return fLargeWorkForkFound;
+}
+
+void SetfLargeWorkInvalidChainFound(bool flag)
+{
+ LOCK(cs_warnings);
+ fLargeWorkInvalidChainFound = flag;
+}
+
+bool GetfLargeWorkInvalidChainFound()
+{
+ LOCK(cs_warnings);
+ return fLargeWorkInvalidChainFound;
+}
+
+std::string GetWarnings(const std::string& strFor)
+{
+ std::string strStatusBar;
+ std::string strRPC;
+ std::string strGUI;
+ const std::string uiAlertSeperator = "<hr />";
+
+ LOCK(cs_warnings);
+
+ if (!CLIENT_VERSION_IS_RELEASE) {
+ strStatusBar = "This is a pre-release test build - use at your own risk - do not use for mining or merchant applications";
+ 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))
+ strStatusBar = strRPC = strGUI = "testsafemode enabled";
+
+ // Misc warnings like out of disk space and clock is wrong
+ if (strMiscWarning != "")
+ {
+ strStatusBar = strMiscWarning;
+ strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + strMiscWarning;
+ }
+
+ if (fLargeWorkForkFound)
+ {
+ strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
+ strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
+ }
+ else if (fLargeWorkInvalidChainFound)
+ {
+ strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
+ strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
+ }
+
+ if (strFor == "gui")
+ return strGUI;
+ else if (strFor == "statusbar")
+ return strStatusBar;
+ else if (strFor == "rpc")
+ return strRPC;
+ assert(!"GetWarnings(): invalid parameter");
+ return "error";
+}
diff --git a/src/warnings.h b/src/warnings.h
new file mode 100644
index 0000000000..a7aa657426
--- /dev/null
+++ b/src/warnings.h
@@ -0,0 +1,21 @@
+// 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_WARNINGS_H
+#define BITCOIN_WARNINGS_H
+
+#include <stdlib.h>
+#include <string>
+
+void SetMiscWarning(const std::string& strWarning);
+void SetfLargeWorkForkFound(bool flag);
+bool GetfLargeWorkForkFound();
+void SetfLargeWorkInvalidChainFound(bool flag);
+bool GetfLargeWorkInvalidChainFound();
+std::string GetWarnings(const std::string& strFor);
+
+static const bool DEFAULT_TESTSAFEMODE = false;
+
+#endif // BITCOIN_WARNINGS_H
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index 8705532429..c063898056 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -6,13 +6,13 @@
#include "zmqpublishnotifier.h"
#include "version.h"
-#include "main.h"
+#include "validation.h"
#include "streams.h"
#include "util.h"
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)
@@ -29,7 +29,7 @@ CZMQNotificationInterface::~CZMQNotificationInterface()
}
}
-CZMQNotificationInterface* CZMQNotificationInterface::CreateWithArguments(const std::map<std::string, std::string> &args)
+CZMQNotificationInterface* CZMQNotificationInterface::Create()
{
CZMQNotificationInterface* notificationInterface = NULL;
std::map<std::string, CZMQNotifierFactory> factories;
@@ -42,11 +42,11 @@ CZMQNotificationInterface* CZMQNotificationInterface::CreateWithArguments(const
for (std::map<std::string, CZMQNotifierFactory>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
{
- std::map<std::string, std::string>::const_iterator j = args.find("-zmq" + i->first);
- if (j!=args.end())
+ std::string arg("-zmq" + i->first);
+ if (IsArgSet(arg))
{
CZMQNotifierFactory factory = i->second;
- std::string address = j->second;
+ std::string address = GetArg(arg, "");
CZMQAbstractNotifier *notifier = factory();
notifier->SetType(i->first);
notifier->SetAddress(address);
@@ -72,7 +72,7 @@ CZMQNotificationInterface* CZMQNotificationInterface::CreateWithArguments(const
// 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,13 +109,13 @@ 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);
@@ -124,12 +124,15 @@ void CZMQNotificationInterface::Shutdown()
}
}
-void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindex)
+void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
{
+ if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones
+ return;
+
for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )
{
CZMQAbstractNotifier *notifier = *i;
- if (notifier->NotifyBlock(pindex))
+ if (notifier->NotifyBlock(pindexNew))
{
i++;
}
@@ -141,8 +144,12 @@ void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindex)
}
}
-void CZMQNotificationInterface::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, const CBlock* pblock)
+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;
@@ -157,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 7b52e7775b..eec6f7bc64 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -8,6 +8,7 @@
#include "validationinterface.h"
#include <string>
#include <map>
+#include <list>
class CBlockIndex;
class CZMQAbstractNotifier;
@@ -17,15 +18,17 @@ class CZMQNotificationInterface : public CValidationInterface
public:
virtual ~CZMQNotificationInterface();
- static CZMQNotificationInterface* CreateWithArguments(const std::map<std::string, std::string> &args);
+ static CZMQNotificationInterface* Create();
protected:
bool Initialize();
void Shutdown();
// CValidationInterface
- void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock);
- void UpdatedBlockTip(const CBlockIndex *pindex);
+ 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 b6c907980f..700c39f66e 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -1,11 +1,14 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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 "chain.h"
#include "chainparams.h"
+#include "streams.h"
#include "zmqpublishnotifier.h"
-#include "main.h"
+#include "validation.h"
#include "util.h"
+#include "rpc/server.h"
static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;
@@ -28,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;
}
@@ -41,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;
}
@@ -51,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;
}
@@ -84,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));
@@ -114,7 +120,7 @@ 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);
@@ -143,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];
@@ -153,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];
@@ -162,10 +168,10 @@ 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);
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
{
LOCK(cs_main);
CBlock block;
@@ -184,8 +190,8 @@ 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());
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ 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 22f02a3d0d..bcbecf1bde 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -12,7 +12,7 @@ class CBlockIndex;
class CZMQAbstractPublishNotifier : public CZMQAbstractNotifier
{
private:
- uint32_t nSequence; //! upcounting per message sequence number
+ uint32_t nSequence; //!< upcounting per message sequence number
public:
diff --git a/test/README.md b/test/README.md
new file mode 100644
index 0000000000..4dd512638d
--- /dev/null
+++ b/test/README.md
@@ -0,0 +1,99 @@
+This directory contains integration tests that test bitcoind and its
+utilities in their entirety. It does not contain unit tests, which
+can be found in [/src/test](/src/test), [/src/wallet/test](/src/wallet/test),
+etc.
+
+There are currently two sets of tests in this directory:
+
+- [functional](/test/functional) which test the functionality of
+bitcoind and bitcoin-qt by interacting with them through the RPC and P2P
+interfaces.
+- [util](test/util) which tests the bitcoin utilities, currently only
+bitcoin-tx.
+
+The util tests are run as part of `make check` target. The functional
+tests are run by the travis continuous build process whenever a pull
+request is opened. Both sets of tests can also be run locally.
+
+Functional Test dependencies
+============================
+The ZMQ functional test requires a python ZMQ library. To install it:
+
+- on Unix, run `sudo apt-get install python3-zmq`
+- on mac OS, run `pip3 install pyzmq`
+
+Running tests locally
+=====================
+
+Build for your system first. Be sure to enable wallet, utils and daemon when you configure. Tests will not run otherwise.
+
+Functional tests
+----------------
+
+You can run any single test by calling
+
+ test/functional/test_runner.py <testname>
+
+Or you can run any combination (incl. duplicates) of tests by calling
+
+ test/functional/test_runner.py <testname1> <testname2> <testname3> ...
+
+Run the regression test suite with
+
+ test/functional/test_runner.py
+
+Run all possible tests with
+
+ test/functional/test_runner.py --extended
+
+By default, tests will be run in parallel. To specify how many jobs to run,
+append `--jobs=n` (default n=4).
+
+If you want to create a basic coverage report for the RPC test suite, append `--coverage`.
+
+Possible options, which apply to each individual test run:
+
+```
+ -h, --help show this help message and exit
+ --nocleanup Leave bitcoinds and test.* datadir on exit or error
+ --noshutdown Don't stop bitcoinds after the test execution
+ --srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli
+ (default: ../../src)
+ --tmpdir=TMPDIR Root directory for datadirs
+ --tracerpc Print out all RPC calls as they are made
+ --coveragedir=COVERAGEDIR
+ Write tested RPC commands into this directory
+```
+
+If you set the environment variable `PYTHON_DEBUG=1` you will get some debug
+output (example: `PYTHON_DEBUG=1 test/functional/test_runner.py wallet`).
+
+A 200-block -regtest blockchain and wallets for four nodes
+is created the first time a regression test is run and
+is stored in the cache/ directory. Each node has 25 mature
+blocks (25*50=1250 BTC) in its wallet.
+
+After the first run, the cache/ blockchain and wallets are
+copied into a temporary directory and used as the initial
+test state.
+
+If you get into a bad state, you should be able
+to recover with:
+
+```bash
+rm -rf cache
+killall bitcoind
+```
+
+Util tests
+----------
+
+Util tests can be run locally by running `test/util/bitcoin-util-test.py`.
+Use the `-v` option for verbose output.
+
+Writing functional tests
+========================
+
+You are encouraged to write functional tests for new or existing features.
+Further information about the functional test framework and individual
+tests is found in [test/functional](/test/functional).
diff --git a/qa/rpc-tests/.gitignore b/test/functional/.gitignore
index cb41d94423..cb41d94423 100644
--- a/qa/rpc-tests/.gitignore
+++ b/test/functional/.gitignore
diff --git a/qa/rpc-tests/README.md b/test/functional/README.md
index 651b01f18a..e6c4849702 100644
--- a/qa/rpc-tests/README.md
+++ b/test/functional/README.md
@@ -59,7 +59,7 @@ thread.)
* RPC calls are available in p2p tests.
* Can be used to write free-form tests, where specific p2p-protocol behavior
-is tested. Examples: ```p2p-accept-block.py```, ```maxblocksinflight.py```.
+is tested. Examples: ```p2p-accept-block.py```, ```p2p-compactblocks.py```.
## Comptool
diff --git a/qa/rpc-tests/abandonconflict.py b/test/functional/abandonconflict.py
index c50c3cc562..9748757641 100755
--- a/qa/rpc-tests/abandonconflict.py
+++ b/test/functional/abandonconflict.py
@@ -2,23 +2,23 @@
# Copyright (c) 2014-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.
-
-
+"""Test the abandontransaction RPC.
+
+ The abandontransaction RPC marks a transaction and all its in-wallet
+ descendants as abandoned which allows their inputs to be respent. It can be
+ used to replace "stuck" or evicted transactions. It only works on transactions
+ which are not included in a block and are not currently in the mempool. It has
+ no effect on transactions which are already conflicted or abandoned.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-import urllib.parse
class AbandonConflictTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = False
-
- def setup_network(self):
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.00001"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-logtimemicros"]))
- connect_nodes(self.nodes[0], 1)
+ self.extra_args = [["-minrelaytxfee=0.00001"], []]
def run_test(self):
self.nodes[1].generate(100)
@@ -35,8 +35,8 @@ class AbandonConflictTest(BitcoinTestFramework):
assert(balance - newbalance < Decimal("0.001")) #no more than fees lost
balance = newbalance
- url = urllib.parse.urlparse(self.nodes[1].url)
- self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1)))
+ # Disconnect nodes so node0's transactions don't get into node1's mempool
+ disconnect_nodes(self.nodes[0], 1)
# Identify the 10btc outputs
nA = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txA, 1)["vout"]) if vout["value"] == Decimal("10"))
@@ -68,26 +68,26 @@ class AbandonConflictTest(BitcoinTestFramework):
# In mempool txs from self should increase balance from change
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance - Decimal("30") + Decimal("24.9996"))
+ assert_equal(newbalance, balance - Decimal("30") + Decimal("24.9996"))
balance = newbalance
# Restart the node with a higher min relay fee so the parent tx is no longer in mempool
# TODO: redo with eviction
- # Note had to make sure tx did not have AllowFree priority
stop_node(self.nodes[0],0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"])
+ self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
- # Verify txs no longer in mempool
- assert(len(self.nodes[0].getrawmempool()) == 0)
+ # Verify txs no longer in either node's mempool
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
+ assert_equal(len(self.nodes[1].getrawmempool()), 0)
# Not in mempool txs from self should only reduce balance
# inputs are still spent, but change not received
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance - Decimal("24.9996"))
+ assert_equal(newbalance, balance - Decimal("24.9996"))
# Unconfirmed received funds that are not in mempool, also shouldn't show
# up in unconfirmed balance
unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()
- assert(unconfbalance == newbalance)
+ assert_equal(unconfbalance, newbalance)
# Also shouldn't show up in listunspent
assert(not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)])
balance = newbalance
@@ -96,35 +96,35 @@ class AbandonConflictTest(BitcoinTestFramework):
# including that the child tx was also abandoned
self.nodes[0].abandontransaction(txAB1)
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance + Decimal("30"))
+ assert_equal(newbalance, balance + Decimal("30"))
balance = newbalance
# Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned
stop_node(self.nodes[0],0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.00001"])
- assert(len(self.nodes[0].getrawmempool()) == 0)
- assert(self.nodes[0].getbalance() == balance)
+ self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"])
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
+ assert_equal(self.nodes[0].getbalance(), balance)
# But if its received again then it is unabandoned
# And since now in mempool, the change is available
# But its child tx remains abandoned
self.nodes[0].sendrawtransaction(signed["hex"])
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance - Decimal("20") + Decimal("14.99998"))
+ assert_equal(newbalance, balance - Decimal("20") + Decimal("14.99998"))
balance = newbalance
# Send child tx again so its unabandoned
self.nodes[0].sendrawtransaction(signed2["hex"])
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance - Decimal("10") - Decimal("14.99998") + Decimal("24.9996"))
+ assert_equal(newbalance, balance - Decimal("10") - Decimal("14.99998") + Decimal("24.9996"))
balance = newbalance
# Remove using high relay fee again
stop_node(self.nodes[0],0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"])
- assert(len(self.nodes[0].getrawmempool()) == 0)
+ self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance - Decimal("24.9996"))
+ assert_equal(newbalance, balance - Decimal("24.9996"))
balance = newbalance
# Create a double spend of AB1 by spending again from only A's 10 output
@@ -143,7 +143,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance + Decimal("20"))
+ assert_equal(newbalance, balance + Decimal("20"))
balance = newbalance
# There is currently a minor bug around this and so this test doesn't work. See Issue #7315
@@ -151,10 +151,10 @@ class AbandonConflictTest(BitcoinTestFramework):
# Don't think C's should either
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
newbalance = self.nodes[0].getbalance()
- #assert(newbalance == balance - Decimal("10"))
- print("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
- print("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
- print(str(balance) + " -> " + str(newbalance) + " ?")
+ #assert_equal(newbalance, balance - Decimal("10"))
+ self.log.info("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
+ self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
+ self.log.info(str(balance) + " -> " + str(newbalance) + " ?")
if __name__ == '__main__':
AbandonConflictTest().main()
diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py
new file mode 100755
index 0000000000..8e301c4379
--- /dev/null
+++ b/test/functional/assumevalid.py
@@ -0,0 +1,202 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+"""Test logic for skipping signature validation on old blocks.
+
+Test logic for skipping signature validation on blocks which we've assumed
+valid (https://github.com/bitcoin/bitcoin/pull/9484)
+
+We build a chain that includes and invalid signature for one of the
+transactions:
+
+ 0: genesis block
+ 1: block 1 with coinbase transaction output.
+ 2-101: bury that block with 100 blocks so the coinbase transaction
+ output can be spent
+ 102: a block containing a transaction spending the coinbase
+ transaction output. The transaction has an invalid signature.
+ 103-2202: bury the bad block with just over two weeks' worth of blocks
+ (2100 blocks)
+
+Start three nodes:
+
+ - node0 has no -assumevalid parameter. Try to sync to block 2202. It will
+ reject block 102 and only sync as far as block 101
+ - node1 has -assumevalid set to the hash of block 102. Try to sync to
+ block 2202. node1 will sync all the way to block 2202.
+ - node2 has -assumevalid set to the hash of block 102. Try to sync to
+ block 200. node2 will reject block 102 since it's assumed valid, but it
+ isn't buried by at least two weeks' work.
+"""
+import time
+
+from test_framework.blocktools import (create_block, create_coinbase)
+from test_framework.key import CECKey
+from test_framework.mininode import (CBlockHeader,
+ COutPoint,
+ CTransaction,
+ CTxIn,
+ CTxOut,
+ NetworkThread,
+ NodeConn,
+ NodeConnCB,
+ msg_block,
+ msg_headers)
+from test_framework.script import (CScript, OP_TRUE)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (start_node, p2p_port, assert_equal)
+
+class BaseNode(NodeConnCB):
+ def send_header_for_blocks(self, new_blocks):
+ headers_message = msg_headers()
+ headers_message.headers = [CBlockHeader(b) for b in new_blocks]
+ self.send_message(headers_message)
+
+class AssumeValidTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+
+ def setup_network(self):
+ # Start node0. We don't start the other nodes yet since
+ # we need to pre-mine a block with an invalid transaction
+ # signature so we can pass in the block hash as assumevalid.
+ self.nodes = [start_node(0, self.options.tmpdir)]
+
+ def send_blocks_until_disconnected(self, node):
+ """Keep sending blocks to the node until we're disconnected."""
+ for i in range(len(self.blocks)):
+ try:
+ node.send_message(msg_block(self.blocks[i]))
+ except IOError as e:
+ assert str(e) == 'Not connected, no pushbuf'
+ break
+
+ def assert_blockchain_height(self, node, height):
+ """Wait until the blockchain is no longer advancing and verify it's reached the expected height."""
+ last_height = node.getblock(node.getbestblockhash())['height']
+ timeout = 10
+ while True:
+ time.sleep(0.25)
+ current_height = node.getblock(node.getbestblockhash())['height']
+ if current_height != last_height:
+ last_height = current_height
+ if timeout < 0:
+ assert False, "blockchain too short after timeout: %d" % current_height
+ timeout - 0.25
+ continue
+ elif current_height > height:
+ assert False, "blockchain too long: %d" % current_height
+ elif current_height == height:
+ break
+
+ def run_test(self):
+
+ # Connect to node0
+ node0 = BaseNode()
+ connections = []
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
+ node0.add_connection(connections[0])
+
+ NetworkThread().start() # Start up network handling in another thread
+ node0.wait_for_verack()
+
+ # Build the blockchain
+ self.tip = int(self.nodes[0].getbestblockhash(), 16)
+ self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
+
+ self.blocks = []
+
+ # Get a pubkey for the coinbase TXO
+ coinbase_key = CECKey()
+ coinbase_key.set_secretbytes(b"horsebattery")
+ coinbase_pubkey = coinbase_key.get_pubkey()
+
+ # Create the first block with a coinbase output to our key
+ height = 1
+ block = create_block(self.tip, create_coinbase(height, coinbase_pubkey), self.block_time)
+ self.blocks.append(block)
+ self.block_time += 1
+ block.solve()
+ # Save the coinbase for later
+ self.block1 = block
+ self.tip = block.sha256
+ height += 1
+
+ # Bury the block 100 deep so the coinbase output is spendable
+ for i in range(100):
+ block = create_block(self.tip, create_coinbase(height), self.block_time)
+ block.solve()
+ self.blocks.append(block)
+ self.tip = block.sha256
+ self.block_time += 1
+ height += 1
+
+ # Create a transaction spending the coinbase output with an invalid (null) signature
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.block1.vtx[0].sha256, 0), scriptSig=b""))
+ tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE])))
+ tx.calc_sha256()
+
+ block102 = create_block(self.tip, create_coinbase(height), self.block_time)
+ self.block_time += 1
+ block102.vtx.extend([tx])
+ block102.hashMerkleRoot = block102.calc_merkle_root()
+ block102.rehash()
+ block102.solve()
+ self.blocks.append(block102)
+ self.tip = block102.sha256
+ self.block_time += 1
+ height += 1
+
+ # Bury the assumed valid block 2100 deep
+ for i in range(2100):
+ block = create_block(self.tip, create_coinbase(height), self.block_time)
+ block.nVersion = 4
+ block.solve()
+ self.blocks.append(block)
+ self.tip = block.sha256
+ self.block_time += 1
+ height += 1
+
+ # Start node1 and node2 with assumevalid so they accept a block with a bad signature.
+ self.nodes.append(start_node(1, self.options.tmpdir,
+ ["-assumevalid=" + hex(block102.sha256)]))
+ node1 = BaseNode() # connects to node1
+ connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], node1))
+ node1.add_connection(connections[1])
+ node1.wait_for_verack()
+
+ self.nodes.append(start_node(2, self.options.tmpdir,
+ ["-assumevalid=" + hex(block102.sha256)]))
+ node2 = BaseNode() # connects to node2
+ connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2))
+ node2.add_connection(connections[2])
+ node2.wait_for_verack()
+
+ # send header lists to all three nodes
+ node0.send_header_for_blocks(self.blocks[0:2000])
+ node0.send_header_for_blocks(self.blocks[2000:])
+ node1.send_header_for_blocks(self.blocks[0:2000])
+ node1.send_header_for_blocks(self.blocks[2000:])
+ node2.send_header_for_blocks(self.blocks[0:200])
+
+ # Send blocks to node0. Block 102 will be rejected.
+ self.send_blocks_until_disconnected(node0)
+ self.assert_blockchain_height(self.nodes[0], 101)
+
+ # Send all blocks to node1. All blocks will be accepted.
+ for i in range(2202):
+ node1.send_message(msg_block(self.blocks[i]))
+ # Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
+ node1.sync_with_ping(120)
+ assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)
+
+ # Send blocks to node2. Block 102 will be rejected.
+ self.send_blocks_until_disconnected(node2)
+ self.assert_blockchain_height(self.nodes[2], 101)
+
+if __name__ == '__main__':
+ AssumeValidTest().main()
diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/test/functional/bip65-cltv-p2p.py
index 754b6873b7..bb83042f35 100755
--- a/qa/rpc-tests/bip65-cltv-p2p.py
+++ b/test/functional/bip65-cltv-p2p.py
@@ -2,6 +2,19 @@
# Copyright (c) 2015-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.
+"""Test BIP65 (CHECKLOCKTIMEVERIFY).
+
+Connect to a single node.
+Mine 2 (version 3) blocks (save the coinbases for later).
+Generate 98 more version 3 blocks, verify the node accepts.
+Mine 749 version 4 blocks, verify the node accepts.
+Check that the new CLTV rules are not enforced on the 750th version 4 block.
+Check that the new CLTV rules are enforced on the 751st version 4 block.
+Mine 199 new version blocks.
+Mine 1 old-version block.
+Mine 1 new version block.
+Mine 1 old version block, see that the node rejects.
+"""
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import *
@@ -20,31 +33,13 @@ def cltv_invalidate(tx):
tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP] +
list(CScript(tx.vin[0].scriptSig)))
-'''
-This test is meant to exercise BIP65 (CHECKLOCKTIMEVERIFY)
-Connect to a single node.
-Mine 2 (version 3) blocks (save the coinbases for later).
-Generate 98 more version 3 blocks, verify the node accepts.
-Mine 749 version 4 blocks, verify the node accepts.
-Check that the new CLTV rules are not enforced on the 750th version 4 block.
-Check that the new CLTV rules are enforced on the 751st version 4 block.
-Mine 199 new version blocks.
-Mine 1 old-version block.
-Mine 1 new version block.
-Mine 1 old version block, see that the node rejects.
-'''
class BIP65Test(ComparisonTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 1
-
- def setup_network(self):
- # Must set the blockversion for this test
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=3']],
- binary=[self.options.testbinary])
+ self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=3']]
def run_test(self):
test = TestManager(self, self.options.tmpdir)
@@ -71,9 +66,9 @@ class BIP65Test(ComparisonTestFramework):
self.nodeaddress = self.nodes[0].getnewaddress()
self.last_block_time = int(time.time())
- ''' 98 more version 3 blocks '''
+ ''' 398 more version 3 blocks '''
test_blocks = []
- for i in range(98):
+ for i in range(398):
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
block.nVersion = 3
block.rehash()
@@ -118,24 +113,6 @@ class BIP65Test(ComparisonTestFramework):
height += 1
yield TestInstance([[block, True]])
- '''
- Check that the new CLTV rules are enforced in the 751st version 4
- block.
- '''
- spendtx = self.create_transaction(self.nodes[0],
- self.coinbase_blocks[1], self.nodeaddress, 1.0)
- cltv_invalidate(spendtx)
- spendtx.rehash()
-
- block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
- block.nVersion = 4
- block.vtx.append(spendtx)
- block.hashMerkleRoot = block.calc_merkle_root()
- block.rehash()
- block.solve()
- self.last_block_time += 1
- yield TestInstance([[block, False]])
-
''' Mine 199 new version blocks on last valid tip '''
test_blocks = []
for i in range(199):
@@ -169,6 +146,24 @@ class BIP65Test(ComparisonTestFramework):
height += 1
yield TestInstance([[block, True]])
+ '''
+ Check that the new CLTV rules are enforced in the 951st version 4
+ block.
+ '''
+ spendtx = self.create_transaction(self.nodes[0],
+ self.coinbase_blocks[1], self.nodeaddress, 1.0)
+ cltv_invalidate(spendtx)
+ spendtx.rehash()
+
+ block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
+ block.nVersion = 4
+ block.vtx.append(spendtx)
+ block.hashMerkleRoot = block.calc_merkle_root()
+ block.rehash()
+ block.solve()
+ self.last_block_time += 1
+ yield TestInstance([[block, False]])
+
''' Mine 1 old version block, should be invalid '''
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
block.nVersion = 3
diff --git a/qa/rpc-tests/bip65-cltv.py b/test/functional/bip65-cltv.py
index abba7fc20e..ddf932c746 100755
--- a/qa/rpc-tests/bip65-cltv.py
+++ b/test/functional/bip65-cltv.py
@@ -2,10 +2,7 @@
# Copyright (c) 2015-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.
-
-#
-# Test the CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic
-#
+"""Test the CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -15,22 +12,20 @@ class BIP65Test(BitcoinTestFramework):
super().__init__()
self.num_nodes = 3
self.setup_clean_chain = False
+ self.extra_args = [[], ["-blockversion=3"], ["-blockversion=4"]]
def setup_network(self):
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, []))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=3"]))
- self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=4"]))
+ self.setup_nodes()
connect_nodes(self.nodes[1], 0)
connect_nodes(self.nodes[2], 0)
- self.is_network_split = False
self.sync_all()
def run_test(self):
cnt = self.nodes[0].getblockcount()
# Mine some old-version blocks
- self.nodes[1].generate(100)
+ self.nodes[1].generate(200)
+ cnt += 100
self.sync_all()
if (self.nodes[0].getblockcount() != cnt + 100):
raise AssertionError("Failed to mine 100 version=3 blocks")
@@ -71,12 +66,8 @@ class BIP65Test(BitcoinTestFramework):
if (self.nodes[0].getblockcount() != cnt + 1051):
raise AssertionError("Failed to mine a version=4 block")
- # Mine 1 old-version blocks
- try:
- self.nodes[1].generate(1)
- raise AssertionError("Succeeded to mine a version=3 block after 950 version=4 blocks")
- except JSONRPCException:
- pass
+ # Mine 1 old-version blocks. This should fail
+ assert_raises_jsonrpc(-1,"CreateNewBlock: TestBlockValidity failed: bad-version(0x00000003)", self.nodes[1].generate, 1)
self.sync_all()
if (self.nodes[0].getblockcount() != cnt + 1051):
raise AssertionError("Accepted a version=3 block after 950 version=4 blocks")
diff --git a/qa/rpc-tests/bip68-112-113-p2p.py b/test/functional/bip68-112-113-p2p.py
index 55b3e2a04a..5a322e8c0e 100755
--- a/qa/rpc-tests/bip68-112-113-p2p.py
+++ b/test/functional/bip68-112-113-p2p.py
@@ -1,19 +1,9 @@
#!/usr/bin/env python3
-# Copyright (c) 2015 The Bitcoin Core developers
+# Copyright (c) 2015-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.
+"""Test activation of the first version bits soft fork.
-from test_framework.test_framework import ComparisonTestFramework
-from test_framework.util import *
-from test_framework.mininode import ToHex, CTransaction, NetworkThread
-from test_framework.blocktools import create_coinbase, create_block
-from test_framework.comptool import TestInstance, TestManager
-from test_framework.script import *
-from io import BytesIO
-import time
-
-'''
-This test is meant to exercise activation of the first version bits soft fork
This soft fork will activate the following BIPS:
BIP 68 - nSequence relative lock times
BIP 112 - CHECKSEQUENCEVERIFY
@@ -51,7 +41,16 @@ bip112txs_vary_nSequence_9 - 16 txs with nSequence relative_locktimes of 9 evalu
bip112txs_vary_OP_CSV - 16 txs with nSequence = 10 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP
bip112txs_vary_OP_CSV_9 - 16 txs with nSequence = 9 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP
bip112tx_special - test negative argument to OP_CSV
-'''
+"""
+
+from test_framework.test_framework import ComparisonTestFramework
+from test_framework.util import *
+from test_framework.mininode import ToHex, CTransaction, NetworkThread
+from test_framework.blocktools import create_coinbase, create_block
+from test_framework.comptool import TestInstance, TestManager
+from test_framework.script import *
+from io import BytesIO
+import time
base_relative_locktime = 10
seq_disable_flag = 1<<31
@@ -96,12 +95,7 @@ class BIP68_112_113Test(ComparisonTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 1
-
- def setup_network(self):
- # Must set the blockversion for this test
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=4']],
- binary=[self.options.testbinary])
+ self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4']]
def run_test(self):
test = TestManager(self, self.options.tmpdir)
@@ -289,6 +283,7 @@ class BIP68_112_113Test(ComparisonTestFramework):
# BIP113 test transaction will be modified before each use to put in appropriate block time
bip113tx_v1 = self.create_transaction(self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98"))
bip113tx_v1.vin[0].nSequence = 0xFFFFFFFE
+ bip113tx_v1.nVersion = 1
bip113tx_v2 = self.create_transaction(self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98"))
bip113tx_v2.vin[0].nSequence = 0xFFFFFFFE
bip113tx_v2.nVersion = 2
diff --git a/qa/rpc-tests/bip68-sequence.py b/test/functional/bip68-sequence.py
index a12bf10ebd..db66b7719c 100755
--- a/qa/rpc-tests/bip68-sequence.py
+++ b/test/functional/bip68-sequence.py
@@ -2,15 +2,10 @@
# Copyright (c) 2014-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.
-
-#
-# Test BIP68 implementation
-#
+"""Test BIP68 implementation."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-from test_framework.script import *
-from test_framework.mininode import *
from test_framework.blocktools import *
SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)
@@ -26,41 +21,34 @@ class BIP68Test(BitcoinTestFramework):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = False
+ self.extra_args = [[], ["-acceptnonstdtxn=0"]]
- def setup_network(self):
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-blockprioritysize=0"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-blockprioritysize=0", "-acceptnonstdtxn=0"]))
- self.is_network_split = False
+ def run_test(self):
self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
- connect_nodes(self.nodes[0], 1)
- def run_test(self):
# Generate some coins
self.nodes[0].generate(110)
- print("Running test disable flag")
+ self.log.info("Running test disable flag")
self.test_disable_flag()
- print("Running test sequence-lock-confirmed-inputs")
+ self.log.info("Running test sequence-lock-confirmed-inputs")
self.test_sequence_lock_confirmed_inputs()
- print("Running test sequence-lock-unconfirmed-inputs")
+ self.log.info("Running test sequence-lock-unconfirmed-inputs")
self.test_sequence_lock_unconfirmed_inputs()
- print("Running test BIP68 not consensus before versionbits activation")
+ self.log.info("Running test BIP68 not consensus before versionbits activation")
self.test_bip68_not_consensus()
- print("Verifying nVersion=2 transactions aren't standard")
- self.test_version2_relay(before_activation=True)
-
- print("Activating BIP68 (and 112/113)")
+ self.log.info("Activating BIP68 (and 112/113)")
self.activateCSV()
- print("Verifying nVersion=2 transactions are now standard")
- self.test_version2_relay(before_activation=False)
+ self.log.info("Verifying nVersion=2 transactions are standard.")
+ self.log.info("Note that nVersion=2 transactions are always standard (independent of BIP68 activation status).")
+ self.test_version2_relay()
- print("Passed\n")
+ self.log.info("Passed")
# Test that BIP68 is not in effect if tx version is 1, or if
# the first sequence bit is set.
@@ -97,12 +85,7 @@ class BIP68Test(BitcoinTestFramework):
tx2.vout = [CTxOut(int(value-self.relayfee*COIN), CScript([b'a']))]
tx2.rehash()
- try:
- self.nodes[0].sendrawtransaction(ToHex(tx2))
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], NOT_FINAL_ERROR)
- else:
- assert(False)
+ assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx2))
# Setting the version back down to 1 should disable the sequence lock,
# so this should be accepted.
@@ -197,14 +180,12 @@ class BIP68Test(BitcoinTestFramework):
tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), CScript([b'a'])))
rawtx = self.nodes[0].signrawtransaction(ToHex(tx))["hex"]
- try:
- self.nodes[0].sendrawtransaction(rawtx)
- except JSONRPCException as exp:
- assert(not should_pass and using_sequence_locks)
- assert_equal(exp.error["message"], NOT_FINAL_ERROR)
+ if (using_sequence_locks and not should_pass):
+ # This transaction should be rejected
+ assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, rawtx)
else:
- assert(should_pass or not using_sequence_locks)
- # Recalculate utxos if we successfully sent the transaction
+ # This raw transaction should be accepted
+ self.nodes[0].sendrawtransaction(rawtx)
utxos = self.nodes[0].listunspent()
# Test that sequence locks on unconfirmed inputs must have nSequence
@@ -246,14 +227,13 @@ class BIP68Test(BitcoinTestFramework):
tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee*COIN), CScript([b'a']))]
tx.rehash()
- try:
- node.sendrawtransaction(ToHex(tx))
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], NOT_FINAL_ERROR)
- assert(orig_tx.hash in node.getrawmempool())
+ if (orig_tx.hash in node.getrawmempool()):
+ # sendrawtransaction should fail if the tx is in the mempool
+ assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, node.sendrawtransaction, ToHex(tx))
else:
- # orig_tx must not be in mempool
- assert(orig_tx.hash not in node.getrawmempool())
+ # sendrawtransaction should succeed if the tx is not in the mempool
+ node.sendrawtransaction(ToHex(tx))
+
return tx
test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)
@@ -261,7 +241,7 @@ class BIP68Test(BitcoinTestFramework):
# Now mine some blocks, but make sure tx2 doesn't get mined.
# Use prioritisetransaction to lower the effective feerate to 0
- self.nodes[0].prioritisetransaction(tx2.hash, -1e15, int(-self.relayfee*COIN))
+ self.nodes[0].prioritisetransaction(tx2.hash, int(-self.relayfee*COIN))
cur_time = int(time.time())
for i in range(10):
self.nodes[0].setmocktime(cur_time + 600)
@@ -274,7 +254,7 @@ class BIP68Test(BitcoinTestFramework):
test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)
# Mine tx2, and then try again
- self.nodes[0].prioritisetransaction(tx2.hash, 1e15, int(self.relayfee*COIN))
+ self.nodes[0].prioritisetransaction(tx2.hash, int(self.relayfee*COIN))
# Advance the time on the node so that we can test timelocks
self.nodes[0].setmocktime(cur_time+600)
@@ -302,12 +282,7 @@ class BIP68Test(BitcoinTestFramework):
tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN)
raw_tx5 = self.nodes[0].signrawtransaction(ToHex(tx5))["hex"]
- try:
- self.nodes[0].sendrawtransaction(raw_tx5)
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], NOT_FINAL_ERROR)
- else:
- assert(False)
+ assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5)
# Test mempool-BIP68 consistency after reorg
#
@@ -380,12 +355,7 @@ class BIP68Test(BitcoinTestFramework):
tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))]
tx3.rehash()
- try:
- self.nodes[0].sendrawtransaction(ToHex(tx3))
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], NOT_FINAL_ERROR)
- else:
- assert(False)
+ assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3))
# make a block that violates bip68; ensure that the tip updates
tip = int(self.nodes[0].getbestblockhash(), 16)
@@ -403,13 +373,13 @@ class BIP68Test(BitcoinTestFramework):
# activation should happen at block height 432 (3 periods)
min_activation_height = 432
height = self.nodes[0].getblockcount()
- assert(height < 432)
- self.nodes[0].generate(432-height)
+ assert(height < min_activation_height)
+ self.nodes[0].generate(min_activation_height-height)
assert(get_bip9_status(self.nodes[0], 'csv')['status'] == 'active')
sync_blocks(self.nodes)
- # Use self.nodes[1] to test standardness relay policy
- def test_version2_relay(self, before_activation):
+ # Use self.nodes[1] to test that version 2 transactions are standard.
+ def test_version2_relay(self):
inputs = [ ]
outputs = { self.nodes[1].getnewaddress() : 1.0 }
rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
@@ -417,12 +387,7 @@ class BIP68Test(BitcoinTestFramework):
tx = FromHex(CTransaction(), rawtxfund)
tx.nVersion = 2
tx_signed = self.nodes[1].signrawtransaction(ToHex(tx))["hex"]
- try:
- tx_id = self.nodes[1].sendrawtransaction(tx_signed)
- assert(before_activation == False)
- except:
- assert(before_activation)
-
+ tx_id = self.nodes[1].sendrawtransaction(tx_signed)
if __name__ == '__main__':
BIP68Test().main()
diff --git a/qa/rpc-tests/bip9-softforks.py b/test/functional/bip9-softforks.py
index 979d1410c2..1b2dff63d2 100755
--- a/qa/rpc-tests/bip9-softforks.py
+++ b/test/functional/bip9-softforks.py
@@ -1,21 +1,9 @@
#!/usr/bin/env python3
-# Copyright (c) 2015 The Bitcoin Core developers
+# Copyright (c) 2015-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.
+"""Test BIP 9 soft forks.
-from test_framework.blockstore import BlockStore
-from test_framework.test_framework import ComparisonTestFramework
-from test_framework.util import *
-from test_framework.mininode import CTransaction, NetworkThread
-from test_framework.blocktools import create_coinbase, create_block
-from test_framework.comptool import TestInstance, TestManager
-from test_framework.script import CScript, OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP
-from io import BytesIO
-import time
-import itertools
-
-'''
-This test is meant to exercise BIP forks
Connect to a single node.
regtest lock-in with 108/144 block signalling
activation after a further 144 blocks
@@ -26,19 +14,24 @@ mine 108 blocks signalling readiness and 36 blocks not signalling readiness (STA
mine a further 143 blocks (LOCKED_IN)
test that enforcement has not triggered (which triggers ACTIVE)
test that enforcement has triggered
-'''
+"""
+from test_framework.test_framework import ComparisonTestFramework
+from test_framework.util import *
+from test_framework.mininode import CTransaction, NetworkThread
+from test_framework.blocktools import create_coinbase, create_block
+from test_framework.comptool import TestInstance, TestManager
+from test_framework.script import CScript, OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP
+from io import BytesIO
+import time
+import itertools
class BIP9SoftForksTest(ComparisonTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 1
-
- def setup_network(self):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1']],
- binary=[self.options.testbinary])
+ self.extra_args = [['-whitelist=127.0.0.1']]
def run_test(self):
self.test = TestManager(self, self.options.tmpdir)
@@ -81,6 +74,9 @@ class BIP9SoftForksTest(ComparisonTestFramework):
return info['bip9_softforks'][key]
def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignature, bitno):
+ assert_equal(self.get_bip9_status(bipName)['status'], 'defined')
+ assert_equal(self.get_bip9_status(bipName)['since'], 0)
+
# generate some coins for later
self.coinbase_blocks = self.nodes[0].generate(2)
self.height = 3 # height of the next block to build
@@ -89,6 +85,7 @@ class BIP9SoftForksTest(ComparisonTestFramework):
self.last_block_time = int(time.time())
assert_equal(self.get_bip9_status(bipName)['status'], 'defined')
+ assert_equal(self.get_bip9_status(bipName)['since'], 0)
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName not in tmpl['rules'])
assert(bipName not in tmpl['vbavailable'])
@@ -101,6 +98,7 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance(test_blocks, sync_every_block=False)
assert_equal(self.get_bip9_status(bipName)['status'], 'started')
+ assert_equal(self.get_bip9_status(bipName)['since'], 144)
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName not in tmpl['rules'])
assert_equal(tmpl['vbavailable'][bipName], bitno)
@@ -117,6 +115,7 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance(test_blocks, sync_every_block=False)
assert_equal(self.get_bip9_status(bipName)['status'], 'started')
+ assert_equal(self.get_bip9_status(bipName)['since'], 144)
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName not in tmpl['rules'])
assert_equal(tmpl['vbavailable'][bipName], bitno)
@@ -133,6 +132,7 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance(test_blocks, sync_every_block=False)
assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in')
+ assert_equal(self.get_bip9_status(bipName)['since'], 432)
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName not in tmpl['rules'])
@@ -142,6 +142,7 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance(test_blocks, sync_every_block=False)
assert_equal(self.get_bip9_status(bipName)['status'], 'locked_in')
+ assert_equal(self.get_bip9_status(bipName)['since'], 432)
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName not in tmpl['rules'])
@@ -167,6 +168,7 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance([[block, True]])
assert_equal(self.get_bip9_status(bipName)['status'], 'active')
+ assert_equal(self.get_bip9_status(bipName)['since'], 576)
tmpl = self.nodes[0].getblocktemplate({})
assert(bipName in tmpl['rules'])
assert(bipName not in tmpl['vbavailable'])
@@ -193,17 +195,14 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance([[block, False]])
# Restart all
- self.test.block_store.close()
+ self.test.clear_all_connections()
stop_nodes(self.nodes)
- wait_bitcoinds()
- shutil.rmtree(self.options.tmpdir)
+ shutil.rmtree(self.options.tmpdir + "/node0")
self.setup_chain()
self.setup_network()
- self.test.block_store = BlockStore(self.options.tmpdir)
- self.test.clear_all_connections()
self.test.add_all_connections(self.nodes)
- NetworkThread().start() # Start up network handling in another thread
-
+ NetworkThread().start()
+ self.test.test_nodes[0].wait_for_verack()
def get_tests(self):
for test in itertools.chain(
@@ -217,21 +216,21 @@ class BIP9SoftForksTest(ComparisonTestFramework):
return
def csv_invalidate(self, tx):
- '''Modify the signature in vin 0 of the tx to fail CSV
+ """Modify the signature in vin 0 of the tx to fail CSV
Prepends -1 CSV DROP in the scriptSig itself.
- '''
+ """
tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP] +
list(CScript(tx.vin[0].scriptSig)))
def sequence_lock_invalidate(self, tx):
- '''Modify the nSequence to make it fails once sequence lock rule is activated (high timespan)
- '''
+ """Modify the nSequence to make it fails once sequence lock rule is
+ activated (high timespan).
+ """
tx.vin[0].nSequence = 0x00FFFFFF
tx.nLockTime = 0
def mtp_invalidate(self, tx):
- '''Modify the nLockTime to make it fails once MTP rule is activated
- '''
+ """Modify the nLockTime to make it fails once MTP rule is activated."""
# Disable Sequence lock, Activate nLockTime
tx.vin[0].nSequence = 0x90FFFFFF
tx.nLockTime = self.last_block_time
diff --git a/qa/rpc-tests/bipdersig-p2p.py b/test/functional/bipdersig-p2p.py
index 4e4936a4ae..31c7ebba90 100755
--- a/qa/rpc-tests/bipdersig-p2p.py
+++ b/test/functional/bipdersig-p2p.py
@@ -2,6 +2,19 @@
# Copyright (c) 2015-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.
+"""Test BIP66 (DER SIG).
+
+Connect to a single node.
+Mine 2 (version 2) blocks (save the coinbases for later).
+Generate 98 more version 2 blocks, verify the node accepts.
+Mine 749 version 3 blocks, verify the node accepts.
+Check that the new DERSIG rules are not enforced on the 750th version 3 block.
+Check that the new DERSIG rules are enforced on the 751st version 3 block.
+Mine 199 new version blocks.
+Mine 1 old-version block.
+Mine 1 new version block.
+Mine 1 old version block, see that the node rejects.
+"""
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import *
@@ -15,10 +28,10 @@ import time
# A canonical signature consists of:
# <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
def unDERify(tx):
- '''
+ """
Make the signature in vin 0 of a tx non-DER-compliant,
by adding padding after the S-value.
- '''
+ """
scriptSig = CScript(tx.vin[0].scriptSig)
newscript = []
for i in scriptSig:
@@ -27,20 +40,6 @@ def unDERify(tx):
else:
newscript.append(i)
tx.vin[0].scriptSig = CScript(newscript)
-
-'''
-This test is meant to exercise BIP66 (DER SIG).
-Connect to a single node.
-Mine 2 (version 2) blocks (save the coinbases for later).
-Generate 98 more version 2 blocks, verify the node accepts.
-Mine 749 version 3 blocks, verify the node accepts.
-Check that the new DERSIG rules are not enforced on the 750th version 3 block.
-Check that the new DERSIG rules are enforced on the 751st version 3 block.
-Mine 199 new version blocks.
-Mine 1 old-version block.
-Mine 1 new version block.
-Mine 1 old version block, see that the node rejects.
-'''
class BIP66Test(ComparisonTestFramework):
@@ -48,12 +47,6 @@ class BIP66Test(ComparisonTestFramework):
super().__init__()
self.num_nodes = 1
- def setup_network(self):
- # Must set the blockversion for this test
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=2']],
- binary=[self.options.testbinary])
-
def run_test(self):
test = TestManager(self, self.options.tmpdir)
test.add_all_connections(self.nodes)
@@ -79,9 +72,9 @@ class BIP66Test(ComparisonTestFramework):
self.nodeaddress = self.nodes[0].getnewaddress()
self.last_block_time = int(time.time())
- ''' 98 more version 2 blocks '''
+ ''' 298 more version 2 blocks '''
test_blocks = []
- for i in range(98):
+ for i in range(298):
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
block.nVersion = 2
block.rehash()
@@ -124,25 +117,7 @@ class BIP66Test(ComparisonTestFramework):
self.last_block_time += 1
self.tip = block.sha256
height += 1
- yield TestInstance([[block, True]])
-
- '''
- Check that the new DERSIG rules are enforced in the 751st version 3
- block.
- '''
- spendtx = self.create_transaction(self.nodes[0],
- self.coinbase_blocks[1], self.nodeaddress, 1.0)
- unDERify(spendtx)
- spendtx.rehash()
-
- block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
- block.nVersion = 3
- block.vtx.append(spendtx)
- block.hashMerkleRoot = block.calc_merkle_root()
- block.rehash()
- block.solve()
- self.last_block_time += 1
- yield TestInstance([[block, False]])
+ yield TestInstance([[block, True]])
''' Mine 199 new version blocks on last valid tip '''
test_blocks = []
@@ -177,6 +152,24 @@ class BIP66Test(ComparisonTestFramework):
height += 1
yield TestInstance([[block, True]])
+ '''
+ Check that the new DERSIG rules are enforced in the 951st version 3
+ block.
+ '''
+ spendtx = self.create_transaction(self.nodes[0],
+ self.coinbase_blocks[1], self.nodeaddress, 1.0)
+ unDERify(spendtx)
+ spendtx.rehash()
+
+ block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
+ block.nVersion = 3
+ block.vtx.append(spendtx)
+ block.hashMerkleRoot = block.calc_merkle_root()
+ block.rehash()
+ block.solve()
+ self.last_block_time += 1
+ yield TestInstance([[block, False]])
+
''' Mine 1 old version block, should be invalid '''
block = create_block(self.tip, create_coinbase(height), self.last_block_time + 1)
block.nVersion = 2
diff --git a/qa/rpc-tests/bipdersig.py b/test/functional/bipdersig.py
index 17c2ced79a..41f88fb664 100755
--- a/qa/rpc-tests/bipdersig.py
+++ b/test/functional/bipdersig.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-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.
-
-#
-# Test the BIP66 changeover logic
-#
+"""Test the BIP66 changeover logic."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -15,15 +12,12 @@ class BIP66Test(BitcoinTestFramework):
super().__init__()
self.num_nodes = 3
self.setup_clean_chain = False
+ self.extra_args = [[], ["-blockversion=2"], ["-blockversion=3"]]
def setup_network(self):
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, []))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=2"]))
- self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=3"]))
+ self.setup_nodes()
connect_nodes(self.nodes[1], 0)
connect_nodes(self.nodes[2], 0)
- self.is_network_split = False
self.sync_all()
def run_test(self):
@@ -71,12 +65,8 @@ class BIP66Test(BitcoinTestFramework):
if (self.nodes[0].getblockcount() != cnt + 1051):
raise AssertionError("Failed to mine a version=3 block")
- # Mine 1 old-version blocks
- try:
- self.nodes[1].generate(1)
- raise AssertionError("Succeeded to mine a version=2 block after 950 version=3 blocks")
- except JSONRPCException:
- pass
+ # Mine 1 old-version blocks. This should fail
+ assert_raises_jsonrpc(-1, "CreateNewBlock: TestBlockValidity failed: bad-version(0x00000002)", self.nodes[1].generate, 1)
self.sync_all()
if (self.nodes[0].getblockcount() != cnt + 1051):
raise AssertionError("Accepted a version=2 block after 950 version=3 blocks")
diff --git a/qa/rpc-tests/blockchain.py b/test/functional/blockchain.py
index 410b85d15e..8596f1edaf 100755
--- a/qa/rpc-tests/blockchain.py
+++ b/test/functional/blockchain.py
@@ -2,49 +2,43 @@
# Copyright (c) 2014-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.
+"""Test RPCs related to blockchainstate.
-#
-# Test RPC calls related to blockchain state. Tests correspond to code in
-# rpc/blockchain.cpp.
-#
+Test the following RPCs:
+ - gettxoutsetinfo
+ - getdifficulty
+ - getbestblockhash
+ - getblockhash
+ - getblockheader
+ - getnetworkhashps
+ - verifychain
+
+Tests correspond to code in rpc/blockchain.cpp.
+"""
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.authproxy import JSONRPCException
from test_framework.util import (
assert_equal,
- assert_raises,
+ assert_raises_jsonrpc,
assert_is_hex_string,
assert_is_hash_string,
- start_nodes,
- connect_nodes_bi,
)
class BlockchainTest(BitcoinTestFramework):
- """
- Test blockchain-related RPC calls:
-
- - gettxoutsetinfo
- - verifychain
-
- """
def __init__(self):
super().__init__()
self.setup_clean_chain = False
self.num_nodes = 2
- def setup_network(self, split=False):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
- connect_nodes_bi(self.nodes, 0, 1)
- self.is_network_split = False
- self.sync_all()
-
def run_test(self):
self._test_gettxoutsetinfo()
self._test_getblockheader()
+ self._test_getdifficulty()
+ self._test_getnetworkhashps()
self.nodes[0].verifychain(4, 0)
def _test_gettxoutsetinfo(self):
@@ -62,8 +56,8 @@ class BlockchainTest(BitcoinTestFramework):
def _test_getblockheader(self):
node = self.nodes[0]
- assert_raises(
- JSONRPCException, lambda: node.getblockheader('nonsense'))
+ assert_raises_jsonrpc(-5, "Block not found",
+ node.getblockheader, "nonsense")
besthash = node.getbestblockhash()
secondbesthash = node.getblockhash(199)
@@ -85,5 +79,16 @@ class BlockchainTest(BitcoinTestFramework):
assert isinstance(int(header['versionHex'], 16), int)
assert isinstance(header['difficulty'], Decimal)
+ def _test_getdifficulty(self):
+ difficulty = self.nodes[0].getdifficulty()
+ # 1 hash in 2 should be valid, so difficulty should be 1/2**31
+ # binary => decimal => binary math is why we do this check
+ assert abs(difficulty * 2**31 - 1) < 0.0001
+
+ def _test_getnetworkhashps(self):
+ hashes_per_second = self.nodes[0].getnetworkhashps()
+ # This should be 2 hashes every 10 minutes or 1/300
+ assert abs(hashes_per_second * 300 - 1) < 0.0001
+
if __name__ == '__main__':
BlockchainTest().main()
diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py
new file mode 100755
index 0000000000..54fd7740c1
--- /dev/null
+++ b/test/functional/bumpfee.py
@@ -0,0 +1,303 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Test the bumpfee RPC.
+
+Verifies that the bumpfee RPC creates replacement transactions successfully when
+its preconditions are met, and returns appropriate errors in other cases.
+
+This module consists of around a dozen individual test cases implemented in the
+top-level functions named as test_<test_case_description>. The test functions
+can be disabled or reordered if needed for debugging. If new test cases are
+added in the the future, they should try to follow the same convention and not
+make assumptions about execution order.
+"""
+
+from segwit import send_to_witness
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework import blocktools
+from test_framework.mininode import CTransaction
+from test_framework.util import *
+
+import io
+
+# Sequence number that is BIP 125 opt-in and BIP 68-compliant
+BIP125_SEQUENCE_NUMBER = 0xfffffffd
+
+WALLET_PASSPHRASE = "test"
+WALLET_PASSPHRASE_TIMEOUT = 3600
+
+
+class BumpFeeTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = True
+
+ def setup_network(self, split=False):
+ extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)]
+ for i in range(self.num_nodes)]
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+
+ # Encrypt wallet for test_locked_wallet_fails test
+ self.nodes[1].encryptwallet(WALLET_PASSPHRASE)
+ bitcoind_processes[1].wait()
+ self.nodes[1] = start_node(1, self.options.tmpdir, extra_args[1])
+ self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
+
+ connect_nodes_bi(self.nodes, 0, 1)
+ self.sync_all()
+
+ def run_test(self):
+ peer_node, rbf_node = self.nodes
+ rbf_node_address = rbf_node.getnewaddress()
+
+ # fund rbf node with 10 coins of 0.001 btc (100,000 satoshis)
+ self.log.info("Mining blocks...")
+ peer_node.generate(110)
+ self.sync_all()
+ for i in range(25):
+ peer_node.sendtoaddress(rbf_node_address, 0.001)
+ self.sync_all()
+ peer_node.generate(1)
+ self.sync_all()
+ assert_equal(rbf_node.getbalance(), Decimal("0.025"))
+
+ self.log.info("Running tests")
+ dest_address = peer_node.getnewaddress()
+ test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address)
+ test_segwit_bumpfee_succeeds(rbf_node, dest_address)
+ test_nonrbf_bumpfee_fails(peer_node, dest_address)
+ test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address)
+ test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address)
+ test_small_output_fails(rbf_node, dest_address)
+ test_dust_to_fee(rbf_node, dest_address)
+ test_settxfee(rbf_node, dest_address)
+ test_rebumping(rbf_node, dest_address)
+ test_rebumping_not_replaceable(rbf_node, dest_address)
+ test_unconfirmed_not_spendable(rbf_node, rbf_node_address)
+ test_bumpfee_metadata(rbf_node, dest_address)
+ test_locked_wallet_fails(rbf_node, dest_address)
+ self.log.info("Success")
+
+
+def test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address):
+ rbfid = spend_one_input(rbf_node, dest_address)
+ rbftx = rbf_node.gettransaction(rbfid)
+ sync_mempools((rbf_node, peer_node))
+ assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool()
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ assert bumped_tx["fee"] - abs(rbftx["fee"]) > 0
+ # check that bumped_tx propogates, original tx was evicted and has a wallet conflict
+ sync_mempools((rbf_node, peer_node))
+ assert bumped_tx["txid"] in rbf_node.getrawmempool()
+ assert bumped_tx["txid"] in peer_node.getrawmempool()
+ assert rbfid not in rbf_node.getrawmempool()
+ assert rbfid not in peer_node.getrawmempool()
+ oldwtx = rbf_node.gettransaction(rbfid)
+ assert len(oldwtx["walletconflicts"]) > 0
+ # check wallet transaction replaces and replaced_by values
+ bumpedwtx = rbf_node.gettransaction(bumped_tx["txid"])
+ assert_equal(oldwtx["replaced_by_txid"], bumped_tx["txid"])
+ assert_equal(bumpedwtx["replaces_txid"], rbfid)
+
+
+def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
+ # Create a transaction with segwit output, then create an RBF transaction
+ # which spends it, and make sure bumpfee can be called on it.
+
+ segwit_in = next(u for u in rbf_node.listunspent() if u["amount"] == Decimal("0.001"))
+ segwit_out = rbf_node.validateaddress(rbf_node.getnewaddress())
+ rbf_node.addwitnessaddress(segwit_out["address"])
+ segwitid = send_to_witness(
+ use_p2wsh=False,
+ node=rbf_node,
+ utxo=segwit_in,
+ pubkey=segwit_out["pubkey"],
+ encode_p2sh=False,
+ amount=Decimal("0.0009"),
+ sign=True)
+
+ rbfraw = rbf_node.createrawtransaction([{
+ 'txid': segwitid,
+ 'vout': 0,
+ "sequence": BIP125_SEQUENCE_NUMBER
+ }], {dest_address: Decimal("0.0005"),
+ rbf_node.getrawchangeaddress(): Decimal("0.0003")})
+ rbfsigned = rbf_node.signrawtransaction(rbfraw)
+ rbfid = rbf_node.sendrawtransaction(rbfsigned["hex"])
+ assert rbfid in rbf_node.getrawmempool()
+
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ assert bumped_tx["txid"] in rbf_node.getrawmempool()
+ assert rbfid not in rbf_node.getrawmempool()
+
+
+def test_nonrbf_bumpfee_fails(peer_node, dest_address):
+ # cannot replace a non RBF transaction (from node which did not enable RBF)
+ not_rbfid = peer_node.sendtoaddress(dest_address, Decimal("0.00090000"))
+ assert_raises_jsonrpc(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid)
+
+
+def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
+ # cannot bump fee unless the tx has only inputs that we own.
+ # here, the rbftx has a peer_node coin and then adds a rbf_node input
+ # Note that this test depends upon the RPC code checking input ownership prior to change outputs
+ # (since it can't use fundrawtransaction, it lacks a proper change output)
+ utxos = [node.listunspent()[-1] for node in (rbf_node, peer_node)]
+ inputs = [{
+ "txid": utxo["txid"],
+ "vout": utxo["vout"],
+ "address": utxo["address"],
+ "sequence": BIP125_SEQUENCE_NUMBER
+ } for utxo in utxos]
+ output_val = sum(utxo["amount"] for utxo in utxos) - Decimal("0.001")
+ rawtx = rbf_node.createrawtransaction(inputs, {dest_address: output_val})
+ signedtx = rbf_node.signrawtransaction(rawtx)
+ signedtx = peer_node.signrawtransaction(signedtx["hex"])
+ rbfid = rbf_node.sendrawtransaction(signedtx["hex"])
+ assert_raises_jsonrpc(-4, "Transaction contains inputs that don't belong to this wallet",
+ rbf_node.bumpfee, rbfid)
+
+
+def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address):
+ # cannot bump fee if the transaction has a descendant
+ # parent is send-to-self, so we don't have to check which output is change when creating the child tx
+ parent_id = spend_one_input(rbf_node, rbf_node_address)
+ tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000})
+ tx = rbf_node.signrawtransaction(tx)
+ txid = rbf_node.sendrawtransaction(tx["hex"])
+ assert_raises_jsonrpc(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
+
+
+def test_small_output_fails(rbf_node, dest_address):
+ # cannot bump fee with a too-small output
+ rbfid = spend_one_input(rbf_node, dest_address)
+ rbf_node.bumpfee(rbfid, {"totalFee": 50000})
+
+ rbfid = spend_one_input(rbf_node, dest_address)
+ assert_raises_jsonrpc(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 50001})
+
+
+def test_dust_to_fee(rbf_node, dest_address):
+ # check that if output is reduced to dust, it will be converted to fee
+ # the bumped tx sets fee=49,900, but it converts to 50,000
+ rbfid = spend_one_input(rbf_node, dest_address)
+ fulltx = rbf_node.getrawtransaction(rbfid, 1)
+ bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 49900})
+ full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1)
+ assert_equal(bumped_tx["fee"], Decimal("0.00050000"))
+ assert_equal(len(fulltx["vout"]), 2)
+ assert_equal(len(full_bumped_tx["vout"]), 1) #change output is eliminated
+
+
+def test_settxfee(rbf_node, dest_address):
+ # check that bumpfee reacts correctly to the use of settxfee (paytxfee)
+ rbfid = spend_one_input(rbf_node, dest_address)
+ requested_feerate = Decimal("0.00025000")
+ rbf_node.settxfee(requested_feerate)
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ actual_feerate = bumped_tx["fee"] * 1000 / rbf_node.getrawtransaction(bumped_tx["txid"], True)["size"]
+ # Assert that the difference between the requested feerate and the actual
+ # feerate of the bumped transaction is small.
+ assert_greater_than(Decimal("0.00001000"), abs(requested_feerate - actual_feerate))
+ rbf_node.settxfee(Decimal("0.00000000")) # unset paytxfee
+
+
+def test_rebumping(rbf_node, dest_address):
+ # check that re-bumping the original tx fails, but bumping the bumper succeeds
+ rbfid = spend_one_input(rbf_node, dest_address)
+ bumped = rbf_node.bumpfee(rbfid, {"totalFee": 2000})
+ assert_raises_jsonrpc(-4, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 3000})
+ rbf_node.bumpfee(bumped["txid"], {"totalFee": 3000})
+
+
+def test_rebumping_not_replaceable(rbf_node, dest_address):
+ # check that re-bumping a non-replaceable bump tx fails
+ rbfid = spend_one_input(rbf_node, dest_address)
+ bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False})
+ assert_raises_jsonrpc(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
+ {"totalFee": 20000})
+
+
+def test_unconfirmed_not_spendable(rbf_node, rbf_node_address):
+ # check that unconfirmed outputs from bumped transactions are not spendable
+ rbfid = spend_one_input(rbf_node, rbf_node_address)
+ rbftx = rbf_node.gettransaction(rbfid)["hex"]
+ assert rbfid in rbf_node.getrawmempool()
+ bumpid = rbf_node.bumpfee(rbfid)["txid"]
+ assert bumpid in rbf_node.getrawmempool()
+ assert rbfid not in rbf_node.getrawmempool()
+
+ # check that outputs from the bump transaction are not spendable
+ # due to the replaces_txid check in CWallet::AvailableCoins
+ assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == bumpid], [])
+
+ # submit a block with the rbf tx to clear the bump tx out of the mempool,
+ # then call abandon to make sure the wallet doesn't attempt to resubmit the
+ # bump tx, then invalidate the block so the rbf tx will be put back in the
+ # mempool. this makes it possible to check whether the rbf tx outputs are
+ # spendable before the rbf tx is confirmed.
+ block = submit_block_with_tx(rbf_node, rbftx)
+ rbf_node.abandontransaction(bumpid)
+ rbf_node.invalidateblock(block.hash)
+ assert bumpid not in rbf_node.getrawmempool()
+ assert rbfid in rbf_node.getrawmempool()
+
+ # check that outputs from the rbf tx are not spendable before the
+ # transaction is confirmed, due to the replaced_by_txid check in
+ # CWallet::AvailableCoins
+ assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == rbfid], [])
+
+ # check that the main output from the rbf tx is spendable after confirmed
+ rbf_node.generate(1)
+ assert_equal(
+ sum(1 for t in rbf_node.listunspent(minconf=0, include_unsafe=False)
+ if t["txid"] == rbfid and t["address"] == rbf_node_address and t["spendable"]), 1)
+
+
+def test_bumpfee_metadata(rbf_node, dest_address):
+ rbfid = rbf_node.sendtoaddress(dest_address, Decimal("0.00100000"), "comment value", "to value")
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ bumped_wtx = rbf_node.gettransaction(bumped_tx["txid"])
+ assert_equal(bumped_wtx["comment"], "comment value")
+ assert_equal(bumped_wtx["to"], "to value")
+
+
+def test_locked_wallet_fails(rbf_node, dest_address):
+ rbfid = spend_one_input(rbf_node, dest_address)
+ rbf_node.walletlock()
+ assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first.",
+ rbf_node.bumpfee, rbfid)
+
+
+def spend_one_input(node, dest_address):
+ tx_input = dict(
+ sequence=BIP125_SEQUENCE_NUMBER, **next(u for u in node.listunspent() if u["amount"] == Decimal("0.00100000")))
+ rawtx = node.createrawtransaction(
+ [tx_input], {dest_address: Decimal("0.00050000"),
+ node.getrawchangeaddress(): Decimal("0.00049000")})
+ signedtx = node.signrawtransaction(rawtx)
+ txid = node.sendrawtransaction(signedtx["hex"])
+ return txid
+
+
+def submit_block_with_tx(node, tx):
+ ctx = CTransaction()
+ ctx.deserialize(io.BytesIO(hex_str_to_bytes(tx)))
+
+ tip = node.getbestblockhash()
+ height = node.getblockcount() + 1
+ block_time = node.getblockheader(tip)["mediantime"] + 1
+ block = blocktools.create_block(int(tip, 16), blocktools.create_coinbase(height), block_time)
+ block.vtx.append(ctx)
+ block.rehash()
+ block.hashMerkleRoot = block.calc_merkle_root()
+ block.solve()
+ node.submitblock(bytes_to_hex_str(block.serialize(True)))
+ return block
+
+
+if __name__ == "__main__":
+ BumpFeeTest().main()
diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py
new file mode 100755
index 0000000000..3ca74ea35e
--- /dev/null
+++ b/test/functional/combine_logs.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python3
+"""Combine logs from multiple bitcoin nodes as well as the test_framework log.
+
+This streams the combined log output to stdout. Use combine_logs.py > outputfile
+to write to an outputfile."""
+
+import argparse
+from collections import defaultdict, namedtuple
+import heapq
+import itertools
+import os
+import re
+import sys
+
+# Matches on the date format at the start of the log event
+TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{6}")
+
+LogEvent = namedtuple('LogEvent', ['timestamp', 'source', 'event'])
+
+def main():
+ """Main function. Parses args, reads the log files and renders them as text or html."""
+
+ parser = argparse.ArgumentParser(usage='%(prog)s [options] <test temporary directory>', description=__doc__)
+ parser.add_argument('-c', '--color', dest='color', action='store_true', help='outputs the combined log with events colored by source (requires posix terminal colors. Use less -r for viewing)')
+ parser.add_argument('--html', dest='html', action='store_true', help='outputs the combined log as html. Requires jinja2. pip install jinja2')
+ args, unknown_args = parser.parse_known_args()
+
+ if args.color and os.name != 'posix':
+ print("Color output requires posix terminal colors.")
+ sys.exit(1)
+
+ if args.html and args.color:
+ print("Only one out of --color or --html should be specified")
+ sys.exit(1)
+
+ # There should only be one unknown argument - the path of the temporary test directory
+ if len(unknown_args) != 1:
+ print("Unexpected arguments" + str(unknown_args))
+ sys.exit(1)
+
+ log_events = read_logs(unknown_args[0])
+
+ print_logs(log_events, color=args.color, html=args.html)
+
+def read_logs(tmp_dir):
+ """Reads log files.
+
+ Delegates to generator function get_log_events() to provide individual log events
+ for each of the input log files."""
+
+ files = [("test", "%s/test_framework.log" % tmp_dir)]
+ for i in itertools.count():
+ logfile = "{}/node{}/regtest/debug.log".format(tmp_dir, i)
+ if not os.path.isfile(logfile):
+ break
+ files.append(("node%d" % i, logfile))
+
+ return heapq.merge(*[get_log_events(source, f) for source, f in files])
+
+def get_log_events(source, logfile):
+ """Generator function that returns individual log events.
+
+ Log events may be split over multiple lines. We use the timestamp
+ regex match as the marker for a new log event."""
+ try:
+ with open(logfile, 'r') as infile:
+ event = ''
+ timestamp = ''
+ for line in infile:
+ # skip blank lines
+ if line == '\n':
+ continue
+ # if this line has a timestamp, it's the start of a new log event.
+ time_match = TIMESTAMP_PATTERN.match(line)
+ if time_match:
+ if event:
+ yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())
+ event = line
+ timestamp = time_match.group()
+ # if it doesn't have a timestamp, it's a continuation line of the previous log.
+ else:
+ event += "\n" + line
+ # Flush the final event
+ yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())
+ except FileNotFoundError:
+ print("File %s could not be opened. Continuing without it." % logfile, file=sys.stderr)
+
+def print_logs(log_events, color=False, html=False):
+ """Renders the iterator of log events into text or html."""
+ if not html:
+ colors = defaultdict(lambda: '')
+ if color:
+ colors["test"] = "\033[0;36m" # CYAN
+ colors["node0"] = "\033[0;34m" # BLUE
+ colors["node1"] = "\033[0;32m" # GREEN
+ colors["node2"] = "\033[0;31m" # RED
+ colors["node3"] = "\033[0;33m" # YELLOW
+ colors["reset"] = "\033[0m" # Reset font color
+
+ for event in log_events:
+ print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, event.event, colors["reset"]))
+
+ else:
+ try:
+ import jinja2
+ except ImportError:
+ print("jinja2 not found. Try `pip install jinja2`")
+ sys.exit(1)
+ print(jinja2.Environment(loader=jinja2.FileSystemLoader('./'))
+ .get_template('combined_log_template.html')
+ .render(title="Combined Logs from testcase", log_events=[event._asdict() for event in log_events]))
+
+if __name__ == '__main__':
+ main()
diff --git a/test/functional/combined_log_template.html b/test/functional/combined_log_template.html
new file mode 100644
index 0000000000..c0b854b080
--- /dev/null
+++ b/test/functional/combined_log_template.html
@@ -0,0 +1,40 @@
+<html lang="en">
+<head>
+ <title> {{ title }} </title>
+ <style>
+ ul {
+ list-style-type: none;
+ font-family: monospace;
+ }
+ li {
+ border: 1px solid slategray;
+ margin-bottom: 1px;
+ }
+ li:hover {
+ filter: brightness(85%);
+ }
+ li.log-test {
+ background-color: cyan;
+ }
+ li.log-node0 {
+ background-color: lightblue;
+ }
+ li.log-node1 {
+ background-color: lightgreen;
+ }
+ li.log-node2 {
+ background-color: lightsalmon;
+ }
+ li.log-node3 {
+ background-color: lightyellow;
+ }
+ </style>
+</head>
+<body>
+<ul>
+{% for event in log_events %}
+<li class="log-{{ event.source }}"> {{ event.source }} {{ event.timestamp }} {{event.event}}</li>
+{% endfor %}
+</ul>
+</body>
+</html>
diff --git a/test/functional/config.ini.in b/test/functional/config.ini.in
new file mode 100644
index 0000000000..29586c555d
--- /dev/null
+++ b/test/functional/config.ini.in
@@ -0,0 +1,18 @@
+# Copyright (c) 2013-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.
+
+# These environment variables are set by the build process and read by
+# test/functional/test_runner.py
+
+[environment]
+SRCDIR=@abs_top_srcdir@
+BUILDDIR=@abs_top_builddir@
+EXEEXT=@EXEEXT@
+
+[components]
+# Which components are enabled. These are commented out by `configure` if they were disabled when running config.
+@ENABLE_WALLET_TRUE@ENABLE_WALLET=true
+@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=true
+@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=true
+@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true
diff --git a/qa/rpc-tests/create_cache.py b/test/functional/create_cache.py
index b6161e0917..39c4c0f47e 100755
--- a/qa/rpc-tests/create_cache.py
+++ b/test/functional/create_cache.py
@@ -2,19 +2,26 @@
# Copyright (c) 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.
+"""Create a blockchain cache.
-#
-# Helper script to create the cache
-# (see BitcoinTestFramework.setup_chain)
-#
+Creating a cache of the blockchain speeds up test execution when running
+multiple functional tests. This helper script is executed by test_runner when multiple
+tests are being run in parallel.
+"""
from test_framework.test_framework import BitcoinTestFramework
class CreateCache(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+
+ # Test network and test nodes are not required:
+ self.num_nodes = 0
+ self.nodes = []
+
def setup_network(self):
- # Don't setup any test nodes
- self.options.noshutdown = True
+ pass
def run_test(self):
pass
diff --git a/qa/rpc-tests/decodescript.py b/test/functional/decodescript.py
index 24768c2655..21a9f1223f 100755
--- a/qa/rpc-tests/decodescript.py
+++ b/test/functional/decodescript.py
@@ -2,6 +2,7 @@
# Copyright (c) 2015-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.
+"""Test decoding scripts via decodescript RPC command."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -9,17 +10,12 @@ from test_framework.mininode import *
from io import BytesIO
class DecodeScriptTest(BitcoinTestFramework):
- """Tests decoding scripts via RPC command "decodescript"."""
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
- def setup_network(self, split=False):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
- self.is_network_split = False
-
def decodescript_script_sig(self):
signature = '304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001'
push_signature = '48' + signature
@@ -111,7 +107,7 @@ class DecodeScriptTest(BitcoinTestFramework):
assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
def decoderawtransaction_asm_sighashtype(self):
- """Tests decoding scripts via RPC command "decoderawtransaction".
+ """Test decoding scripts via RPC command "decoderawtransaction".
This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
"""
diff --git a/test/functional/disablewallet.py b/test/functional/disablewallet.py
new file mode 100755
index 0000000000..d344513414
--- /dev/null
+++ b/test/functional/disablewallet.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+# Copyright (c) 2015-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.
+"""Test a node with the -disablewallet option.
+
+- Test that validateaddress RPC works when running with -disablewallet
+- Test that it is not possible to mine to an invalid address.
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+
+class DisableWalletTest (BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+ self.extra_args = [["-disablewallet"]]
+
+ def run_test (self):
+ # Make sure wallet is really disabled
+ assert_raises_jsonrpc(-32601, 'Method not found', self.nodes[0].getwalletinfo)
+ x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
+ assert(x['isvalid'] == False)
+ x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
+ assert(x['isvalid'] == True)
+
+ # Checking mining to an address without a wallet. Generating to a valid address should succeed
+ # but generating to an invalid address will fail.
+ self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
+ assert_raises_jsonrpc(-5, "Invalid address", self.nodes[0].generatetoaddress, 1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
+
+if __name__ == '__main__':
+ DisableWalletTest ().main ()
diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py
new file mode 100755
index 0000000000..f453fc0261
--- /dev/null
+++ b/test/functional/disconnect_ban.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+"""Test node disconnect and ban behavior"""
+import time
+
+from test_framework.mininode import wait_until
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (assert_equal,
+ assert_raises_jsonrpc,
+ connect_nodes_bi,
+ start_node,
+ stop_node,
+ )
+
+class DisconnectBanTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
+
+ def run_test(self):
+ self.log.info("Test setban and listbanned RPCs")
+
+ self.log.info("setban: successfully ban single IP address")
+ assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point
+ self.nodes[1].setban("127.0.0.1", "add")
+ assert wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10)
+ assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point
+ assert_equal(len(self.nodes[1].listbanned()), 1)
+
+ self.log.info("clearbanned: successfully clear ban list")
+ self.nodes[1].clearbanned()
+ assert_equal(len(self.nodes[1].listbanned()), 0)
+ self.nodes[1].setban("127.0.0.0/24", "add")
+
+ self.log.info("setban: fail to ban an already banned subnet")
+ assert_equal(len(self.nodes[1].listbanned()), 1)
+ assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[1].setban, "127.0.0.1", "add")
+
+ self.log.info("setban: fail to ban an invalid subnet")
+ assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[1].setban, "127.0.0.1/42", "add")
+ assert_equal(len(self.nodes[1].listbanned()), 1) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24
+
+ self.log.info("setban remove: fail to unban a non-banned subnet")
+ assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[1].setban, "127.0.0.1", "remove")
+ assert_equal(len(self.nodes[1].listbanned()), 1)
+
+ self.log.info("setban remove: successfully unban subnet")
+ self.nodes[1].setban("127.0.0.0/24", "remove")
+ assert_equal(len(self.nodes[1].listbanned()), 0)
+ self.nodes[1].clearbanned()
+ assert_equal(len(self.nodes[1].listbanned()), 0)
+
+ self.log.info("setban: test persistence across node restart")
+ self.nodes[1].setban("127.0.0.0/32", "add")
+ self.nodes[1].setban("127.0.0.0/24", "add")
+ # Set the mocktime so we can control when bans expire
+ old_time = int(time.time())
+ self.nodes[1].setmocktime(old_time)
+ self.nodes[1].setban("192.168.0.1", "add", 1) # ban for 1 seconds
+ self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds
+ listBeforeShutdown = self.nodes[1].listbanned()
+ assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address'])
+ # Move time forward by 3 seconds so the third ban has expired
+ self.nodes[1].setmocktime(old_time + 3)
+ assert_equal(len(self.nodes[1].listbanned()), 3)
+
+ stop_node(self.nodes[1], 1)
+
+ self.nodes[1] = start_node(1, self.options.tmpdir)
+ listAfterShutdown = self.nodes[1].listbanned()
+ assert_equal("127.0.0.0/24", listAfterShutdown[0]['address'])
+ assert_equal("127.0.0.0/32", listAfterShutdown[1]['address'])
+ assert_equal("/19" in listAfterShutdown[2]['address'], True)
+
+ # Clear ban lists
+ self.nodes[1].clearbanned()
+ connect_nodes_bi(self.nodes, 0, 1)
+
+ self.log.info("Test disconnectnode RPCs")
+
+ self.log.info("disconnectnode: fail to disconnect when calling with address and nodeid")
+ address1 = self.nodes[0].getpeerinfo()[0]['addr']
+ node1 = self.nodes[0].getpeerinfo()[0]['addr']
+ assert_raises_jsonrpc(-32602, "Only one of address and nodeid should be provided.", self.nodes[0].disconnectnode, address=address1, nodeid=node1)
+
+ self.log.info("disconnectnode: fail to disconnect when calling with junk address")
+ assert_raises_jsonrpc(-29, "Node not found in connected nodes", self.nodes[0].disconnectnode, address="221B Baker Street")
+
+ self.log.info("disconnectnode: successfully disconnect node by address")
+ address1 = self.nodes[0].getpeerinfo()[0]['addr']
+ self.nodes[0].disconnectnode(address=address1)
+ assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
+ assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
+
+ self.log.info("disconnectnode: successfully reconnect node")
+ connect_nodes_bi(self.nodes, 0, 1) # reconnect the node
+ assert_equal(len(self.nodes[0].getpeerinfo()), 2)
+ assert [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
+
+ self.log.info("disconnectnode: successfully disconnect node by node id")
+ id1 = self.nodes[0].getpeerinfo()[0]['id']
+ self.nodes[0].disconnectnode(nodeid=id1)
+ assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
+ assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1]
+
+if __name__ == '__main__':
+ DisconnectBanTest().main()
diff --git a/qa/rpc-tests/forknotify.py b/test/functional/forknotify.py
index 5a3f75c808..9db61c8350 100755
--- a/qa/rpc-tests/forknotify.py
+++ b/test/functional/forknotify.py
@@ -2,10 +2,9 @@
# Copyright (c) 2014-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.
-
-#
-# Test -alertnotify
-#
+"""Test the -alertnotify option."""
+import os
+import time
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -17,12 +16,10 @@ class ForkNotifyTest(BitcoinTestFramework):
self.num_nodes = 2
self.setup_clean_chain = False
- alert_filename = None # Set by setup_network
-
def setup_network(self):
self.nodes = []
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
- with open(self.alert_filename, 'w') as f:
+ with open(self.alert_filename, 'w', encoding='utf8'):
pass # Just open then close to create zero-length file
self.nodes.append(start_node(0, self.options.tmpdir,
["-blockversion=2", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]))
@@ -31,7 +28,6 @@ class ForkNotifyTest(BitcoinTestFramework):
["-blockversion=211"]))
connect_nodes(self.nodes[1], 0)
- self.is_network_split = False
self.sync_all()
def run_test(self):
@@ -44,11 +40,18 @@ class ForkNotifyTest(BitcoinTestFramework):
self.nodes[1].generate(1)
self.sync_all()
- with open(self.alert_filename, 'r') as f:
- alert_text = f.read()
+ # Give bitcoind 10 seconds to write the alert notification
+ timeout = 10.0
+ while timeout > 0:
+ if os.path.exists(self.alert_filename) and os.path.getsize(self.alert_filename):
+ break
+ time.sleep(0.1)
+ timeout -= 0.1
+ else:
+ assert False, "-alertnotify did not warn of up-version blocks"
- if len(alert_text) == 0:
- raise AssertionError("-alertnotify did not warn of up-version blocks")
+ with open(self.alert_filename, 'r', encoding='utf8') as f:
+ alert_text = f.read()
# Mine more up-version blocks, should not get more alerts:
self.nodes[1].generate(1)
@@ -56,7 +59,7 @@ class ForkNotifyTest(BitcoinTestFramework):
self.nodes[1].generate(1)
self.sync_all()
- with open(self.alert_filename, 'r') as f:
+ with open(self.alert_filename, 'r', encoding='utf8') as f:
alert_text2 = f.read()
if alert_text != alert_text2:
diff --git a/qa/rpc-tests/fundrawtransaction.py b/test/functional/fundrawtransaction.py
index eeb8476634..9ddafeb611 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/test/functional/fundrawtransaction.py
@@ -2,6 +2,7 @@
# Copyright (c) 2014-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.
+"""Test the fundrawtransaction RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -22,19 +23,14 @@ class RawTransactionsTest(BitcoinTestFramework):
self.num_nodes = 4
def setup_network(self, split=False):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
-
- connect_nodes_bi(self.nodes,0,1)
- connect_nodes_bi(self.nodes,1,2)
- connect_nodes_bi(self.nodes,0,2)
- connect_nodes_bi(self.nodes,0,3)
+ self.setup_nodes()
- self.is_network_split=False
- self.sync_all()
+ connect_nodes_bi(self.nodes, 0, 1)
+ connect_nodes_bi(self.nodes, 1, 2)
+ connect_nodes_bi(self.nodes, 0, 2)
+ connect_nodes_bi(self.nodes, 0, 3)
def run_test(self):
- print("Mining blocks...")
-
min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
# This test is not meant to test fee estimation and we'd like
# to be sure all txs are sent at a consistent desired feerate
@@ -54,6 +50,11 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[0].generate(121)
self.sync_all()
+ # ensure that setting changePosition in fundraw with an exact match is handled properly
+ rawmatch = self.nodes[2].createrawtransaction([], {self.nodes[2].getnewaddress():50})
+ rawmatch = self.nodes[2].fundrawtransaction(rawmatch, {"changePosition":1, "subtractFeeFromOutputs":[0]})
+ assert_equal(rawmatch["changepos"], -1)
+
watchonly_address = self.nodes[0].getnewaddress()
watchonly_pubkey = self.nodes[0].validateaddress(watchonly_address)["pubkey"]
watchonly_amount = Decimal(200)
@@ -181,12 +182,7 @@ class RawTransactionsTest(BitcoinTestFramework):
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
- try:
- self.nodes[2].fundrawtransaction(rawtx, {'foo': 'bar'})
- raise AssertionError("Accepted invalid option foo")
- except JSONRPCException as e:
- assert("Unexpected key foo" in e.error['message'])
-
+ assert_raises_jsonrpc(-3, "Unexpected key foo", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'})
############################################################
# test a fundrawtransaction with an invalid change address #
@@ -199,12 +195,7 @@ class RawTransactionsTest(BitcoinTestFramework):
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
- try:
- self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': 'foobar'})
- raise AssertionError("Accepted invalid bitcoin address")
- except JSONRPCException as e:
- assert("changeAddress must be a valid bitcoin address" in e.error['message'])
-
+ assert_raises_jsonrpc(-5, "changeAddress must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'})
############################################################
# test a fundrawtransaction with a provided change address #
@@ -218,15 +209,10 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
change = self.nodes[2].getnewaddress()
- try:
- rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 2})
- except JSONRPCException as e:
- assert('changePosition out of bounds' == e.error['message'])
- else:
- assert(False)
+ assert_raises_jsonrpc(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2})
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0})
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
- out = dec_tx['vout'][0];
+ out = dec_tx['vout'][0]
assert_equal(change, out['scriptPubKey']['addresses'][0])
@@ -332,19 +318,14 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
- try:
- rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
- raise AssertionError("Spent more than available")
- except JSONRPCException as e:
- assert("Insufficient" in e.error['message'])
-
+ assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx)
############################################################
#compare fee of a standard pubkeyhash transaction
inputs = []
outputs = {self.nodes[1].getnewaddress():1.1}
- rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[0].fundrawtransaction(rawTx)
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[0].fundrawtransaction(rawtx)
#create same transaction over sendtoaddress
txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1)
@@ -359,8 +340,8 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee of a standard pubkeyhash transaction with multiple outputs
inputs = []
outputs = {self.nodes[1].getnewaddress():1.1,self.nodes[1].getnewaddress():1.2,self.nodes[1].getnewaddress():0.1,self.nodes[1].getnewaddress():1.3,self.nodes[1].getnewaddress():0.2,self.nodes[1].getnewaddress():0.3}
- rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[0].fundrawtransaction(rawTx)
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[0].fundrawtransaction(rawtx)
#create same transaction over sendtoaddress
txId = self.nodes[0].sendmany("", outputs)
signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']
@@ -385,8 +366,8 @@ class RawTransactionsTest(BitcoinTestFramework):
inputs = []
outputs = {mSigObj:1.1}
- rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[0].fundrawtransaction(rawTx)
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[0].fundrawtransaction(rawtx)
#create same transaction over sendtoaddress
txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
@@ -418,8 +399,8 @@ class RawTransactionsTest(BitcoinTestFramework):
inputs = []
outputs = {mSigObj:1.1}
- rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[0].fundrawtransaction(rawTx)
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[0].fundrawtransaction(rawtx)
#create same transaction over sendtoaddress
txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
@@ -453,8 +434,8 @@ class RawTransactionsTest(BitcoinTestFramework):
oldBalance = self.nodes[1].getbalance()
inputs = []
outputs = {self.nodes[1].getnewaddress():1.1}
- rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[2].fundrawtransaction(rawTx)
+ rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[2].fundrawtransaction(rawtx)
signedTx = self.nodes[2].signrawtransaction(fundedTx['hex'])
txId = self.nodes[2].sendrawtransaction(signedTx['hex'])
@@ -469,8 +450,9 @@ class RawTransactionsTest(BitcoinTestFramework):
# locked wallet test
self.nodes[1].encryptwallet("test")
self.nodes.pop(1)
- stop_nodes(self.nodes)
- wait_bitcoinds()
+ stop_node(self.nodes[0], 0)
+ stop_node(self.nodes[1], 2)
+ stop_node(self.nodes[2], 3)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
# This test is not meant to test fee estimation and we'd like
@@ -482,24 +464,34 @@ class RawTransactionsTest(BitcoinTestFramework):
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
connect_nodes_bi(self.nodes,0,3)
- self.is_network_split=False
self.sync_all()
- try:
- self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2)
- raise AssertionError("Wallet unlocked without passphrase")
- except JSONRPCException as e:
- assert('walletpassphrase' in e.error['message'])
+ # drain the keypool
+ self.nodes[1].getnewaddress()
+ self.nodes[1].getrawchangeaddress()
+ inputs = []
+ outputs = {self.nodes[0].getnewaddress():1.1}
+ rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
+ # fund a transaction that requires a new key for the change output
+ # creating the key must be impossible because the wallet is locked
+ assert_raises_jsonrpc(-4, "Keypool ran out, please call keypoolrefill first", self.nodes[1].fundrawtransaction, rawtx)
+
+ #refill the keypool
+ self.nodes[1].walletpassphrase("test", 100)
+ self.nodes[1].keypoolrefill(8) #need to refill the keypool to get an internal change address
+ self.nodes[1].walletlock()
+
+ assert_raises_jsonrpc(-13, "walletpassphrase", self.nodes[1].sendtoaddress, self.nodes[0].getnewaddress(), 1.2)
oldBalance = self.nodes[0].getbalance()
inputs = []
outputs = {self.nodes[0].getnewaddress():1.1}
- rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[1].fundrawtransaction(rawTx)
+ rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[1].fundrawtransaction(rawtx)
#now we need to unlock
- self.nodes[1].walletpassphrase("test", 100)
+ self.nodes[1].walletpassphrase("test", 600)
signedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
txId = self.nodes[1].sendrawtransaction(signedTx['hex'])
self.nodes[1].generate(1)
@@ -527,8 +519,8 @@ class RawTransactionsTest(BitcoinTestFramework):
#fund a tx with ~20 small inputs
inputs = []
outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04}
- rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[1].fundrawtransaction(rawTx)
+ rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[1].fundrawtransaction(rawtx)
#create same transaction over sendtoaddress
txId = self.nodes[1].sendmany("", outputs)
@@ -559,8 +551,8 @@ class RawTransactionsTest(BitcoinTestFramework):
inputs = []
outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04}
- rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
- fundedTx = self.nodes[1].fundrawtransaction(rawTx)
+ rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
+ fundedTx = self.nodes[1].fundrawtransaction(rawtx)
fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex'])
self.sync_all()
@@ -635,7 +627,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(len(self.nodes[3].listunspent(1)), 1)
inputs = []
- outputs = {self.nodes[2].getnewaddress() : 1}
+ outputs = {self.nodes[3].getnewaddress() : 1}
rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
result = self.nodes[3].fundrawtransaction(rawtx) # uses min_relay_tx_fee (set by settxfee)
result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee})
@@ -644,5 +636,100 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
+ #############################
+ # Test address reuse option #
+ #############################
+
+ result3 = self.nodes[3].fundrawtransaction(rawtx, {"reserveChangeKey": False})
+ res_dec = self.nodes[0].decoderawtransaction(result3["hex"])
+ changeaddress = ""
+ for out in res_dec['vout']:
+ if out['value'] > 1.0:
+ changeaddress += out['scriptPubKey']['addresses'][0]
+ assert(changeaddress != "")
+ nextaddr = self.nodes[3].getrawchangeaddress()
+ # frt should not have removed the key from the keypool
+ assert(changeaddress == nextaddr)
+
+ result3 = self.nodes[3].fundrawtransaction(rawtx)
+ res_dec = self.nodes[0].decoderawtransaction(result3["hex"])
+ changeaddress = ""
+ for out in res_dec['vout']:
+ if out['value'] > 1.0:
+ changeaddress += out['scriptPubKey']['addresses'][0]
+ assert(changeaddress != "")
+ nextaddr = self.nodes[3].getnewaddress()
+ # Now the change address key should be removed from the keypool
+ assert(changeaddress != nextaddr)
+
+ ######################################
+ # Test subtractFeeFromOutputs option #
+ ######################################
+
+ # Make sure there is exactly one input so coin selection can't skew the result
+ assert_equal(len(self.nodes[3].listunspent(1)), 1)
+
+ inputs = []
+ outputs = {self.nodes[2].getnewaddress(): 1}
+ rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
+
+ result = [self.nodes[3].fundrawtransaction(rawtx), # uses min_relay_tx_fee (set by settxfee)
+ self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": []}), # empty subtraction list
+ self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0]}), # uses min_relay_tx_fee (set by settxfee)
+ self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee}),
+ self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee, "subtractFeeFromOutputs": [0]})]
+
+ dec_tx = [self.nodes[3].decoderawtransaction(tx['hex']) for tx in result]
+ output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)]
+ change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)]
+
+ assert_equal(result[0]['fee'], result[1]['fee'], result[2]['fee'])
+ assert_equal(result[3]['fee'], result[4]['fee'])
+ assert_equal(change[0], change[1])
+ assert_equal(output[0], output[1])
+ assert_equal(output[0], output[2] + result[2]['fee'])
+ assert_equal(change[0] + result[0]['fee'], change[2])
+ assert_equal(output[3], output[4] + result[4]['fee'])
+ assert_equal(change[3] + result[3]['fee'], change[4])
+
+ inputs = []
+ outputs = {self.nodes[2].getnewaddress(): value for value in (1.0, 1.1, 1.2, 1.3)}
+ rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
+
+ result = [self.nodes[3].fundrawtransaction(rawtx),
+ # split the fee between outputs 0, 2, and 3, but not output 1
+ self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0, 2, 3]})]
+
+ dec_tx = [self.nodes[3].decoderawtransaction(result[0]['hex']),
+ self.nodes[3].decoderawtransaction(result[1]['hex'])]
+
+ # Nested list of non-change output amounts for each transaction
+ output = [[out['value'] for i, out in enumerate(d['vout']) if i != r['changepos']]
+ for d, r in zip(dec_tx, result)]
+
+ # List of differences in output amounts between normal and subtractFee transactions
+ share = [o0 - o1 for o0, o1 in zip(output[0], output[1])]
+
+ # output 1 is the same in both transactions
+ assert_equal(share[1], 0)
+
+ # the other 3 outputs are smaller as a result of subtractFeeFromOutputs
+ assert_greater_than(share[0], 0)
+ assert_greater_than(share[2], 0)
+ assert_greater_than(share[3], 0)
+
+ # outputs 2 and 3 take the same share of the fee
+ assert_equal(share[2], share[3])
+
+ # output 0 takes at least as much share of the fee, and no more than 2 satoshis more, than outputs 2 and 3
+ assert_greater_than_or_equal(share[0], share[2])
+ assert_greater_than_or_equal(share[2] + Decimal(2e-8), share[0])
+
+ # the fee is the same in both transactions
+ assert_equal(result[0]['fee'], result[1]['fee'])
+
+ # the total subtracted from the outputs is equal to the fee
+ assert_equal(share[0] + share[2] + share[3], result[0]['fee'])
+
if __name__ == '__main__':
RawTransactionsTest().main()
diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/test/functional/getblocktemplate_longpoll.py
index 3cddf4046a..bbe1dda5f7 100755
--- a/qa/rpc-tests/getblocktemplate_longpoll.py
+++ b/test/functional/getblocktemplate_longpoll.py
@@ -2,6 +2,7 @@
# Copyright (c) 2014-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.
+"""Test longpolling with getblocktemplate."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -22,17 +23,13 @@ class LongpollThread(threading.Thread):
self.node.getblocktemplate({'longpollid':self.longpollid})
class GetBlockTemplateLPTest(BitcoinTestFramework):
- '''
- Test longpolling with getblocktemplate.
- '''
-
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = False
def run_test(self):
- print("Warning: this test will take about 70 seconds in the best case. Be patient.")
+ self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.")
self.nodes[0].generate(10)
templat = self.nodes[0].getblocktemplate()
longpollid = templat['longpollid']
@@ -64,7 +61,9 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
thr = LongpollThread(self.nodes[0])
thr.start()
# generate a random transaction and submit it
- (txid, txhex, fee) = random_transaction(self.nodes, Decimal("1.1"), Decimal("0.0"), Decimal("0.001"), 20)
+ min_relay_fee = self.nodes[0].getnetworkinfo()["relayfee"]
+ # min_relay_fee is fee per 1000 bytes, which should be more than enough.
+ (txid, txhex, fee) = random_transaction(self.nodes, Decimal("1.1"), min_relay_fee, Decimal("0.001"), 20)
# after one minute, every 10 seconds the mempool is probed, so in 80 seconds it should have returned
thr.join(60 + 20)
assert(not thr.is_alive())
diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/test/functional/getblocktemplate_proposals.py
index 7a4f8f8fdc..fca99c7df5 100755
--- a/qa/rpc-tests/getblocktemplate_proposals.py
+++ b/test/functional/getblocktemplate_proposals.py
@@ -2,6 +2,7 @@
# Copyright (c) 2014-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.
+"""Test block proposals with getblocktemplate."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -66,19 +67,12 @@ def assert_template(node, tmpl, txlist, expect):
raise AssertionError('unexpected: %s' % (rsp,))
class GetBlockTemplateProposalTest(BitcoinTestFramework):
- '''
- Test block proposals with getblocktemplate.
- '''
def __init__(self):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = False
- def setup_network(self):
- self.nodes = self.setup_nodes()
- connect_nodes_bi(self.nodes, 0, 1)
-
def run_test(self):
node = self.nodes[0]
node.generate(1) # Mine a block to leave initial block download
@@ -107,7 +101,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
# Test 3: Truncated final tx
lastbyte = txlist[-1].pop()
- assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a')
+ assert_raises_jsonrpc(-22, "Block decode failed", assert_template, node, tmpl, txlist, 'n/a')
txlist[-1].append(lastbyte)
# Test 4: Add an invalid tx to the end (duplicate of gen tx)
@@ -128,7 +122,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
# Test 7: Bad tx count
txlist.append(b'')
- assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a')
+ assert_raises_jsonrpc(-22, 'Block decode failed', assert_template, node, tmpl, txlist, 'n/a')
txlist.pop()
# Test 8: Bad bits
diff --git a/qa/rpc-tests/getchaintips.py b/test/functional/getchaintips.py
index 1c66b8c289..15f96c565f 100755
--- a/qa/rpc-tests/getchaintips.py
+++ b/test/functional/getchaintips.py
@@ -2,10 +2,13 @@
# Copyright (c) 2014-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.
+"""Test the getchaintips RPC.
-# Exercise the getchaintips API. We introduce a network split, work
-# on chains of different lengths, and join the network together again.
-# This gives us two tips, verify that it works.
+- introduce a network split
+- work on chains of different lengths
+- join the network together again
+- verify that getchaintips now returns two chain tips.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -28,7 +31,7 @@ class GetChainTipsTest (BitcoinTestFramework):
self.split_network ()
self.nodes[0].generate(10)
self.nodes[2].generate(20)
- self.sync_all ()
+ self.sync_all([self.nodes[:2], self.nodes[2:]])
tips = self.nodes[1].getchaintips ()
assert_equal (len (tips), 1)
diff --git a/qa/rpc-tests/httpbasics.py b/test/functional/httpbasics.py
index 10bc927e1a..4b32e8d9ca 100755
--- a/qa/rpc-tests/httpbasics.py
+++ b/test/functional/httpbasics.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-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.
-
-#
-# Test rpc http basics
-#
+"""Test the RPC HTTP basics."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -20,7 +17,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
self.setup_clean_chain = False
def setup_network(self):
- self.nodes = self.setup_nodes()
+ self.setup_nodes()
def run_test(self):
diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py
new file mode 100755
index 0000000000..5be095e62d
--- /dev/null
+++ b/test/functional/import-rescan.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+"""Test wallet import RPCs.
+
+Test rescan behavior of importaddress, importpubkey, importprivkey, and
+importmulti RPCs with different types of keys and rescan options.
+
+In the first part of the test, node 0 creates an address for each type of
+import RPC call and sends BTC to it. Then other nodes import the addresses,
+and the test makes listtransactions and getbalance calls to confirm that the
+importing node either did or did not execute rescans picking up the send
+transactions.
+
+In the second part of the test, node 0 sends more BTC to each address, and the
+test makes more listtransactions and getbalance calls to confirm that the
+importing nodes pick up the new transactions regardless of whether rescans
+happened previously.
+"""
+
+from test_framework.authproxy import JSONRPCException
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (start_nodes, connect_nodes, sync_blocks, assert_equal, set_node_times)
+
+import collections
+import enum
+import itertools
+
+Call = enum.Enum("Call", "single multi")
+Data = enum.Enum("Data", "address pub priv")
+Rescan = enum.Enum("Rescan", "no yes late_timestamp")
+
+
+class Variant(collections.namedtuple("Variant", "call data rescan prune")):
+ """Helper for importing one key and verifying scanned transactions."""
+
+ def do_import(self, timestamp):
+ """Call one key import RPC."""
+
+ if self.call == Call.single:
+ if self.data == Data.address:
+ response, error = try_rpc(self.node.importaddress, self.address["address"], self.label,
+ self.rescan == Rescan.yes)
+ elif self.data == Data.pub:
+ response, error = try_rpc(self.node.importpubkey, self.address["pubkey"], self.label,
+ self.rescan == Rescan.yes)
+ elif self.data == Data.priv:
+ response, error = try_rpc(self.node.importprivkey, self.key, self.label, self.rescan == Rescan.yes)
+ assert_equal(response, None)
+ assert_equal(error, {'message': 'Rescan is disabled in pruned mode',
+ 'code': -4} if self.expect_disabled else None)
+ elif self.call == Call.multi:
+ response = self.node.importmulti([{
+ "scriptPubKey": {
+ "address": self.address["address"]
+ },
+ "timestamp": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),
+ "pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [],
+ "keys": [self.key] if self.data == Data.priv else [],
+ "label": self.label,
+ "watchonly": self.data != Data.priv
+ }], {"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)})
+ assert_equal(response, [{"success": True}])
+
+ def check(self, txid=None, amount=None, confirmations=None):
+ """Verify that getbalance/listtransactions return expected values."""
+
+ balance = self.node.getbalance(self.label, 0, True)
+ assert_equal(balance, self.expected_balance)
+
+ txs = self.node.listtransactions(self.label, 10000, 0, True)
+ assert_equal(len(txs), self.expected_txs)
+
+ if txid is not None:
+ tx, = [tx for tx in txs if tx["txid"] == txid]
+ assert_equal(tx["account"], self.label)
+ assert_equal(tx["address"], self.address["address"])
+ assert_equal(tx["amount"], amount)
+ assert_equal(tx["category"], "receive")
+ assert_equal(tx["label"], self.label)
+ assert_equal(tx["txid"], txid)
+ assert_equal(tx["confirmations"], confirmations)
+ assert_equal("trusted" not in tx, True)
+ # Verify the transaction is correctly marked watchonly depending on
+ # whether the transaction pays to an imported public key or
+ # imported private key. The test setup ensures that transaction
+ # inputs will not be from watchonly keys (important because
+ # involvesWatchonly will be true if either the transaction output
+ # or inputs are watchonly).
+ if self.data != Data.priv:
+ assert_equal(tx["involvesWatchonly"], True)
+ else:
+ assert_equal("involvesWatchonly" not in tx, True)
+
+
+# List of Variants for each way a key or address could be imported.
+IMPORT_VARIANTS = [Variant(*variants) for variants in itertools.product(Call, Data, Rescan, (False, True))]
+
+# List of nodes to import keys to. Half the nodes will have pruning disabled,
+# half will have it enabled. Different nodes will be used for imports that are
+# expected to cause rescans, and imports that are not expected to cause
+# rescans, in order to prevent rescans during later imports picking up
+# transactions associated with earlier imports. This makes it easier to keep
+# track of expected balances and transactions.
+ImportNode = collections.namedtuple("ImportNode", "prune rescan")
+IMPORT_NODES = [ImportNode(*fields) for fields in itertools.product((False, True), repeat=2)]
+
+# Rescans start at the earliest block up to 2 hours before the key timestamp.
+TIMESTAMP_WINDOW = 2 * 60 * 60
+
+
+class ImportRescanTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2 + len(IMPORT_NODES)
+
+ def setup_network(self):
+ extra_args = [[] for _ in range(self.num_nodes)]
+ for i, import_node in enumerate(IMPORT_NODES, 2):
+ if import_node.prune:
+ extra_args[i] += ["-prune=1"]
+
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ for i in range(1, self.num_nodes):
+ connect_nodes(self.nodes[i], 0)
+
+ def run_test(self):
+ # Create one transaction on node 0 with a unique amount and label for
+ # each possible type of wallet import RPC.
+ for i, variant in enumerate(IMPORT_VARIANTS):
+ variant.label = "label {} {}".format(i, variant)
+ variant.address = self.nodes[1].validateaddress(self.nodes[1].getnewaddress(variant.label))
+ variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
+ variant.initial_amount = 10 - (i + 1) / 4.0
+ variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
+
+ # Generate a block containing the initial transactions, then another
+ # block further in the future (past the rescan window).
+ self.nodes[0].generate(1)
+ assert_equal(self.nodes[0].getrawmempool(), [])
+ timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"]
+ set_node_times(self.nodes, timestamp + TIMESTAMP_WINDOW + 1)
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+
+ # For each variation of wallet key import, invoke the import RPC and
+ # check the results from getbalance and listtransactions.
+ for variant in IMPORT_VARIANTS:
+ variant.expect_disabled = variant.rescan == Rescan.yes and variant.prune and variant.call == Call.single
+ expect_rescan = variant.rescan == Rescan.yes and not variant.expect_disabled
+ variant.node = self.nodes[2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))]
+ variant.do_import(timestamp)
+ if expect_rescan:
+ variant.expected_balance = variant.initial_amount
+ variant.expected_txs = 1
+ variant.check(variant.initial_txid, variant.initial_amount, 2)
+ else:
+ variant.expected_balance = 0
+ variant.expected_txs = 0
+ variant.check()
+
+ # Create new transactions sending to each address.
+ fee = self.nodes[0].getnetworkinfo()["relayfee"]
+ for i, variant in enumerate(IMPORT_VARIANTS):
+ variant.sent_amount = 10 - (2 * i + 1) / 8.0
+ variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
+
+ # Generate a block containing the new transactions.
+ self.nodes[0].generate(1)
+ assert_equal(self.nodes[0].getrawmempool(), [])
+ sync_blocks(self.nodes)
+
+ # Check the latest results from getbalance and listtransactions.
+ for variant in IMPORT_VARIANTS:
+ if not variant.expect_disabled:
+ variant.expected_balance += variant.sent_amount
+ variant.expected_txs += 1
+ variant.check(variant.sent_txid, variant.sent_amount, 1)
+ else:
+ variant.check()
+
+
+def try_rpc(func, *args, **kwargs):
+ try:
+ return func(*args, **kwargs), None
+ except JSONRPCException as e:
+ return None, e.error
+
+
+if __name__ == "__main__":
+ ImportRescanTest().main()
diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py
new file mode 100755
index 0000000000..9e3491c428
--- /dev/null
+++ b/test/functional/importmulti.py
@@ -0,0 +1,452 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+"""Test the importmulti RPC."""
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+class ImportMultiTest (BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = True
+
+ def setup_network(self):
+ self.setup_nodes()
+
+ def run_test (self):
+ self.log.info("Mining blocks...")
+ self.nodes[0].generate(1)
+ self.nodes[1].generate(1)
+ timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
+
+ # keyword definition
+ PRIV_KEY = 'privkey'
+ PUB_KEY = 'pubkey'
+ ADDRESS_KEY = 'address'
+ SCRIPT_KEY = 'script'
+
+
+ node0_address1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ node0_address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ node0_address3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+
+ #Check only one address
+ assert_equal(node0_address1['ismine'], True)
+
+ #Node 1 sync test
+ assert_equal(self.nodes[1].getblockcount(),1)
+
+ #Address Test - before import
+ address_info = self.nodes[1].validateaddress(node0_address1['address'])
+ assert_equal(address_info['iswatchonly'], False)
+ assert_equal(address_info['ismine'], False)
+
+
+ # RPC importmulti -----------------------------------------------
+
+ # Bitcoin Address
+ self.log.info("Should import an address")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": address['address']
+ },
+ "timestamp": "now",
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], True)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], timestamp)
+ watchonly_address = address['address']
+ watchonly_timestamp = timestamp
+
+ self.log.info("Should not import an invalid address")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": "not valid address",
+ },
+ "timestamp": "now",
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -5)
+ assert_equal(result[0]['error']['message'], 'Invalid address')
+
+ # ScriptPubKey + internal
+ self.log.info("Should import a scriptPubKey with internal flag")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
+ "internal": True
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], True)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], timestamp)
+
+ # ScriptPubKey + !internal
+ self.log.info("Should not import a scriptPubKey without internal flag")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -8)
+ assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
+
+
+ # Address + Public key + !Internal
+ self.log.info("Should import an address with public key")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": address['address']
+ },
+ "timestamp": "now",
+ "pubkeys": [ address['pubkey'] ]
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], True)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], timestamp)
+
+
+ # ScriptPubKey + Public key + internal
+ self.log.info("Should import a scriptPubKey with internal and with public key")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ request = [{
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
+ "pubkeys": [ address['pubkey'] ],
+ "internal": True
+ }]
+ result = self.nodes[1].importmulti(request)
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], True)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], timestamp)
+
+ # ScriptPubKey + Public key + !internal
+ self.log.info("Should not import a scriptPubKey without internal and with public key")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ request = [{
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
+ "pubkeys": [ address['pubkey'] ]
+ }]
+ result = self.nodes[1].importmulti(request)
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -8)
+ assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
+
+ # Address + Private key + !watchonly
+ self.log.info("Should import an address with private key")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": address['address']
+ },
+ "timestamp": "now",
+ "keys": [ self.nodes[0].dumpprivkey(address['address']) ]
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], True)
+ assert_equal(address_assert['timestamp'], timestamp)
+
+ # Address + Private key + watchonly
+ self.log.info("Should not import an address with private key and with watchonly")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": address['address']
+ },
+ "timestamp": "now",
+ "keys": [ self.nodes[0].dumpprivkey(address['address']) ],
+ "watchonly": True
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -8)
+ assert_equal(result[0]['error']['message'], 'Incompatibility found between watchonly and keys')
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
+
+ # ScriptPubKey + Private key + internal
+ self.log.info("Should import a scriptPubKey with internal and with private key")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
+ "keys": [ self.nodes[0].dumpprivkey(address['address']) ],
+ "internal": True
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], True)
+ assert_equal(address_assert['timestamp'], timestamp)
+
+ # ScriptPubKey + Private key + !internal
+ self.log.info("Should not import a scriptPubKey without internal and with private key")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
+ "keys": [ self.nodes[0].dumpprivkey(address['address']) ]
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -8)
+ assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
+
+
+ # P2SH address
+ sig_address_1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ sig_address_2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ sig_address_3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ multi_sig_script = self.nodes[0].createmultisig(2, [sig_address_1['address'], sig_address_2['address'], sig_address_3['pubkey']])
+ self.nodes[1].generate(100)
+ transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
+ self.nodes[1].generate(1)
+ timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
+ transaction = self.nodes[1].gettransaction(transactionid)
+
+ self.log.info("Should import a p2sh")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": multi_sig_script['address']
+ },
+ "timestamp": "now",
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
+ assert_equal(address_assert['isscript'], True)
+ assert_equal(address_assert['iswatchonly'], True)
+ assert_equal(address_assert['timestamp'], timestamp)
+ p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
+ assert_equal(p2shunspent['spendable'], False)
+ assert_equal(p2shunspent['solvable'], False)
+
+
+ # P2SH + Redeem script
+ sig_address_1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ sig_address_2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ sig_address_3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ multi_sig_script = self.nodes[0].createmultisig(2, [sig_address_1['address'], sig_address_2['address'], sig_address_3['pubkey']])
+ self.nodes[1].generate(100)
+ transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
+ self.nodes[1].generate(1)
+ timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
+ transaction = self.nodes[1].gettransaction(transactionid)
+
+ self.log.info("Should import a p2sh with respective redeem script")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": multi_sig_script['address']
+ },
+ "timestamp": "now",
+ "redeemscript": multi_sig_script['redeemScript']
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
+ assert_equal(address_assert['timestamp'], timestamp)
+
+ p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
+ assert_equal(p2shunspent['spendable'], False)
+ assert_equal(p2shunspent['solvable'], True)
+
+
+ # P2SH + Redeem script + Private Keys + !Watchonly
+ sig_address_1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ sig_address_2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ sig_address_3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ multi_sig_script = self.nodes[0].createmultisig(2, [sig_address_1['address'], sig_address_2['address'], sig_address_3['pubkey']])
+ self.nodes[1].generate(100)
+ transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
+ self.nodes[1].generate(1)
+ timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
+ transaction = self.nodes[1].gettransaction(transactionid)
+
+ self.log.info("Should import a p2sh with respective redeem script and private keys")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": multi_sig_script['address']
+ },
+ "timestamp": "now",
+ "redeemscript": multi_sig_script['redeemScript'],
+ "keys": [ self.nodes[0].dumpprivkey(sig_address_1['address']), self.nodes[0].dumpprivkey(sig_address_2['address'])]
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
+ assert_equal(address_assert['timestamp'], timestamp)
+
+ p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
+ assert_equal(p2shunspent['spendable'], False)
+ assert_equal(p2shunspent['solvable'], True)
+
+ # P2SH + Redeem script + Private Keys + Watchonly
+ sig_address_1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ sig_address_2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ sig_address_3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ multi_sig_script = self.nodes[0].createmultisig(2, [sig_address_1['address'], sig_address_2['address'], sig_address_3['pubkey']])
+ self.nodes[1].generate(100)
+ transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
+ self.nodes[1].generate(1)
+ timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
+ transaction = self.nodes[1].gettransaction(transactionid)
+
+ self.log.info("Should import a p2sh with respective redeem script and private keys")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": multi_sig_script['address']
+ },
+ "timestamp": "now",
+ "redeemscript": multi_sig_script['redeemScript'],
+ "keys": [ self.nodes[0].dumpprivkey(sig_address_1['address']), self.nodes[0].dumpprivkey(sig_address_2['address'])],
+ "watchonly": True
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -8)
+ assert_equal(result[0]['error']['message'], 'Incompatibility found between watchonly and keys')
+
+
+ # Address + Public key + !Internal + Wrong pubkey
+ self.log.info("Should not import an address with a wrong public key")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": address['address']
+ },
+ "timestamp": "now",
+ "pubkeys": [ address2['pubkey'] ]
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -5)
+ assert_equal(result[0]['error']['message'], 'Consistency check failed')
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
+
+
+ # ScriptPubKey + Public key + internal + Wrong pubkey
+ self.log.info("Should not import a scriptPubKey with internal and with a wrong public key")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ request = [{
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
+ "pubkeys": [ address2['pubkey'] ],
+ "internal": True
+ }]
+ result = self.nodes[1].importmulti(request)
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -5)
+ assert_equal(result[0]['error']['message'], 'Consistency check failed')
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
+
+
+ # Address + Private key + !watchonly + Wrong private key
+ self.log.info("Should not import an address with a wrong private key")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": address['address']
+ },
+ "timestamp": "now",
+ "keys": [ self.nodes[0].dumpprivkey(address2['address']) ]
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -5)
+ assert_equal(result[0]['error']['message'], 'Consistency check failed')
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
+
+
+ # ScriptPubKey + Private key + internal + Wrong private key
+ self.log.info("Should not import a scriptPubKey with internal and with a wrong private key")
+ address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
+ "keys": [ self.nodes[0].dumpprivkey(address2['address']) ],
+ "internal": True
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -5)
+ assert_equal(result[0]['error']['message'], 'Consistency check failed')
+ address_assert = self.nodes[1].validateaddress(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
+
+
+ # Importing existing watch only address with new timestamp should replace saved timestamp.
+ assert_greater_than(timestamp, watchonly_timestamp)
+ self.log.info("Should replace previously saved watch only timestamp.")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": watchonly_address,
+ },
+ "timestamp": "now",
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(watchonly_address)
+ assert_equal(address_assert['iswatchonly'], True)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], timestamp)
+ watchonly_timestamp = timestamp
+
+
+ # restart nodes to check for proper serialization/deserialization of watch only address
+ stop_nodes(self.nodes)
+ self.nodes = start_nodes(2, self.options.tmpdir)
+ address_assert = self.nodes[1].validateaddress(watchonly_address)
+ assert_equal(address_assert['iswatchonly'], True)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], watchonly_timestamp)
+
+ # Bad or missing timestamps
+ self.log.info("Should throw on invalid or missing timestamp values")
+ assert_raises_message(JSONRPCException, 'Missing required timestamp field for key',
+ self.nodes[1].importmulti, [{
+ "scriptPubKey": address['scriptPubKey'],
+ }])
+ assert_raises_message(JSONRPCException, 'Expected number or "now" timestamp value for key. got type string',
+ self.nodes[1].importmulti, [{
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "",
+ }])
+
+
+if __name__ == '__main__':
+ ImportMultiTest ().main ()
diff --git a/qa/rpc-tests/importprunedfunds.py b/test/functional/importprunedfunds.py
index d86f51b7f3..94753fe431 100755
--- a/qa/rpc-tests/importprunedfunds.py
+++ b/test/functional/importprunedfunds.py
@@ -2,10 +2,10 @@
# Copyright (c) 2014-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.
-
+"""Test the importprunedfunds and removeprunedfunds RPCs."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-import decimal
+
class ImportPrunedFundsTest(BitcoinTestFramework):
@@ -14,20 +14,10 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 2
- def setup_network(self, split=False):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
- connect_nodes_bi(self.nodes,0,1)
- self.is_network_split=False
- self.sync_all()
-
- def run_test (self):
- import time
- begintime = int(time.time())
-
- print("Mining blocks...")
+ def run_test(self):
+ self.log.info("Mining blocks...")
self.nodes[0].generate(101)
- # sync
self.sync_all()
# address
@@ -72,7 +62,6 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex']
proof2 = self.nodes[0].gettxoutproof([txnid2])
-
txnid3 = self.nodes[0].sendtoaddress(address3, 0.025)
self.nodes[0].generate(1)
rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex']
@@ -81,29 +70,23 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
self.sync_all()
#Import with no affiliated address
- try:
- result1 = self.nodes[1].importprunedfunds(rawtxn1, proof1, "")
- except JSONRPCException as e:
- assert('No addresses' in e.error['message'])
- else:
- assert(False)
-
+ assert_raises_jsonrpc(-5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1)
balance1 = self.nodes[1].getbalance("", 0, True)
assert_equal(balance1, Decimal(0))
#Import with affiliated address with no rescan
- self.nodes[1].importaddress(address2, "", False)
- result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2, "")
- balance2 = Decimal(self.nodes[1].getbalance("", 0, True))
+ self.nodes[1].importaddress(address2, "add2", False)
+ result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2)
+ balance2 = self.nodes[1].getbalance("add2", 0, True)
assert_equal(balance2, Decimal('0.05'))
#Import with private key with no rescan
- self.nodes[1].importprivkey(address3_privkey, "", False)
- result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3, "")
- balance3 = Decimal(self.nodes[1].getbalance("", 0, False))
+ self.nodes[1].importprivkey(address3_privkey, "add3", False)
+ result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3)
+ balance3 = self.nodes[1].getbalance("add3", 0, False)
assert_equal(balance3, Decimal('0.025'))
- balance3 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance3 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance3, Decimal('0.075'))
#Addresses Test - after import
@@ -118,26 +101,18 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
assert_equal(address_info['ismine'], True)
#Remove transactions
+ assert_raises_jsonrpc(-8, "Transaction does not exist in wallet.", self.nodes[1].removeprunedfunds, txnid1)
- try:
- self.nodes[1].removeprunedfunds(txnid1)
- except JSONRPCException as e:
- assert('does not exist' in e.error['message'])
- else:
- assert(False)
-
-
- balance1 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance1 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance1, Decimal('0.075'))
-
self.nodes[1].removeprunedfunds(txnid2)
- balance2 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance2 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance2, Decimal('0.025'))
self.nodes[1].removeprunedfunds(txnid3)
- balance3 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance3 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance3, Decimal('0.0'))
if __name__ == '__main__':
- ImportPrunedFundsTest ().main ()
+ ImportPrunedFundsTest().main()
diff --git a/qa/rpc-tests/invalidateblock.py b/test/functional/invalidateblock.py
index 0faadd33ab..c499d57b90 100755
--- a/qa/rpc-tests/invalidateblock.py
+++ b/test/functional/invalidateblock.py
@@ -2,72 +2,62 @@
# Copyright (c) 2014-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.
-
-#
-# Test InvalidateBlock code
-#
+"""Test the invalidateblock RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class InvalidateTest(BitcoinTestFramework):
-
-
+
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 3
def setup_network(self):
- self.nodes = []
- self.is_network_split = False
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug"]))
- self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"]))
-
+ self.setup_nodes()
+
def run_test(self):
- print("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:")
- print("Mine 4 blocks on Node 0")
+ self.log.info("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:")
+ self.log.info("Mine 4 blocks on Node 0")
self.nodes[0].generate(4)
assert(self.nodes[0].getblockcount() == 4)
besthash = self.nodes[0].getbestblockhash()
- print("Mine competing 6 blocks on Node 1")
+ self.log.info("Mine competing 6 blocks on Node 1")
self.nodes[1].generate(6)
assert(self.nodes[1].getblockcount() == 6)
- print("Connect nodes to force a reorg")
+ self.log.info("Connect nodes to force a reorg")
connect_nodes_bi(self.nodes,0,1)
sync_blocks(self.nodes[0:2])
assert(self.nodes[0].getblockcount() == 6)
badhash = self.nodes[1].getblockhash(2)
- print("Invalidate block 2 on node 0 and verify we reorg to node 0's original chain")
+ self.log.info("Invalidate block 2 on node 0 and verify we reorg to node 0's original chain")
self.nodes[0].invalidateblock(badhash)
newheight = self.nodes[0].getblockcount()
newhash = self.nodes[0].getbestblockhash()
if (newheight != 4 or newhash != besthash):
raise AssertionError("Wrong tip for node0, hash %s, height %d"%(newhash,newheight))
- print("\nMake sure we won't reorg to a lower work chain:")
+ self.log.info("Make sure we won't reorg to a lower work chain:")
connect_nodes_bi(self.nodes,1,2)
- print("Sync node 2 to node 1 so both have 6 blocks")
+ self.log.info("Sync node 2 to node 1 so both have 6 blocks")
sync_blocks(self.nodes[1:3])
assert(self.nodes[2].getblockcount() == 6)
- print("Invalidate block 5 on node 1 so its tip is now at 4")
+ self.log.info("Invalidate block 5 on node 1 so its tip is now at 4")
self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5))
assert(self.nodes[1].getblockcount() == 4)
- print("Invalidate block 3 on node 2, so its tip is now 2")
+ self.log.info("Invalidate block 3 on node 2, so its tip is now 2")
self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3))
assert(self.nodes[2].getblockcount() == 2)
- print("..and then mine a block")
+ self.log.info("..and then mine a block")
self.nodes[2].generate(1)
- print("Verify all nodes are at the right height")
+ self.log.info("Verify all nodes are at the right height")
time.sleep(5)
- for i in range(3):
- print(i,self.nodes[i].getblockcount())
- assert(self.nodes[2].getblockcount() == 3)
- assert(self.nodes[0].getblockcount() == 4)
+ assert_equal(self.nodes[2].getblockcount(), 3)
+ assert_equal(self.nodes[0].getblockcount(), 4)
node1height = self.nodes[1].getblockcount()
if node1height < 4:
raise AssertionError("Node 1 reorged to a lower height: %d"%node1height)
diff --git a/qa/rpc-tests/invalidblockrequest.py b/test/functional/invalidblockrequest.py
index 3d8107a76c..eabc0db8df 100755
--- a/qa/rpc-tests/invalidblockrequest.py
+++ b/test/functional/invalidblockrequest.py
@@ -2,6 +2,14 @@
# Copyright (c) 2015-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.
+"""Test node responses to invalid blocks.
+
+In this test we connect to one node over p2p, and test block requests:
+1) Valid blocks should be requested and become chain tip.
+2) Invalid block with duplicated transaction should be re-requested.
+3) Invalid block with bad coinbase value should be rejected and not
+re-requested.
+"""
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import *
@@ -10,15 +18,6 @@ from test_framework.blocktools import *
import copy
import time
-
-'''
-In this test we connect to one node over p2p, and test block requests:
-1) Valid blocks should be requested and become chain tip.
-2) Invalid block with duplicated transaction should be re-requested.
-3) Invalid block with bad coinbase value should be rejected and not
-re-requested.
-'''
-
# Use the ComparisonTestFramework with 1 node: only use --testbinary.
class InvalidBlockRequestTest(ComparisonTestFramework):
diff --git a/qa/rpc-tests/invalidtxrequest.py b/test/functional/invalidtxrequest.py
index 93205d79de..a9ac231f09 100755
--- a/qa/rpc-tests/invalidtxrequest.py
+++ b/test/functional/invalidtxrequest.py
@@ -2,6 +2,10 @@
# Copyright (c) 2015-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.
+"""Test node responses to invalid transactions.
+
+In this test we connect to one node over p2p, and test tx requests.
+"""
from test_framework.test_framework import ComparisonTestFramework
from test_framework.comptool import TestManager, TestInstance, RejectResult
@@ -9,9 +13,6 @@ from test_framework.blocktools import *
import time
-'''
-In this test we connect to one node over p2p, and test tx requests.
-'''
# Use the ComparisonTestFramework with 1 node: only use --testbinary.
class InvalidTxRequestTest(ComparisonTestFramework):
diff --git a/test/functional/keypool.py b/test/functional/keypool.py
new file mode 100755
index 0000000000..c276e64c7c
--- /dev/null
+++ b/test/functional/keypool.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+"""Test the wallet keypool and interaction with wallet encryption/locking."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+class KeyPoolTest(BitcoinTestFramework):
+
+ def run_test(self):
+ nodes = self.nodes
+ addr_before_encrypting = nodes[0].getnewaddress()
+ addr_before_encrypting_data = nodes[0].validateaddress(addr_before_encrypting)
+ wallet_info_old = nodes[0].getwalletinfo()
+ assert(addr_before_encrypting_data['hdmasterkeyid'] == wallet_info_old['hdmasterkeyid'])
+
+ # Encrypt wallet and wait to terminate
+ nodes[0].encryptwallet('test')
+ bitcoind_processes[0].wait()
+ # Restart node 0
+ nodes[0] = start_node(0, self.options.tmpdir)
+ # Keep creating keys
+ addr = nodes[0].getnewaddress()
+ addr_data = nodes[0].validateaddress(addr)
+ wallet_info = nodes[0].getwalletinfo()
+ assert(addr_before_encrypting_data['hdmasterkeyid'] != wallet_info['hdmasterkeyid'])
+ assert(addr_data['hdmasterkeyid'] == wallet_info['hdmasterkeyid'])
+ assert_raises_jsonrpc(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
+
+ # put six (plus 2) new keys in the keypool (100% external-, +100% internal-keys, 1 in min)
+ nodes[0].walletpassphrase('test', 12000)
+ nodes[0].keypoolrefill(6)
+ nodes[0].walletlock()
+ wi = nodes[0].getwalletinfo()
+ assert_equal(wi['keypoolsize_hd_internal'], 6)
+ assert_equal(wi['keypoolsize'], 6)
+
+ # drain the internal keys
+ nodes[0].getrawchangeaddress()
+ nodes[0].getrawchangeaddress()
+ nodes[0].getrawchangeaddress()
+ nodes[0].getrawchangeaddress()
+ nodes[0].getrawchangeaddress()
+ nodes[0].getrawchangeaddress()
+ addr = set()
+ # the next one should fail
+ assert_raises_jsonrpc(-12, "Keypool ran out", nodes[0].getrawchangeaddress)
+
+ # drain the external keys
+ addr.add(nodes[0].getnewaddress())
+ addr.add(nodes[0].getnewaddress())
+ addr.add(nodes[0].getnewaddress())
+ addr.add(nodes[0].getnewaddress())
+ addr.add(nodes[0].getnewaddress())
+ addr.add(nodes[0].getnewaddress())
+ assert(len(addr) == 6)
+ # the next one should fail
+ assert_raises_jsonrpc(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
+
+ # refill keypool with three new addresses
+ nodes[0].walletpassphrase('test', 1)
+ nodes[0].keypoolrefill(3)
+
+ # test walletpassphrase timeout
+ time.sleep(1.1)
+ assert_equal(nodes[0].getwalletinfo()["unlocked_until"], 0)
+
+ # drain them by mining
+ nodes[0].generate(1)
+ nodes[0].generate(1)
+ nodes[0].generate(1)
+ assert_raises_jsonrpc(-12, "Keypool ran out", nodes[0].generate, 1)
+
+ nodes[0].walletpassphrase('test', 100)
+ nodes[0].keypoolrefill(100)
+ wi = nodes[0].getwalletinfo()
+ assert_equal(wi['keypoolsize_hd_internal'], 100)
+ assert_equal(wi['keypoolsize'], 100)
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = False
+ self.num_nodes = 1
+
+if __name__ == '__main__':
+ KeyPoolTest().main()
diff --git a/test/functional/listsinceblock.py b/test/functional/listsinceblock.py
new file mode 100755
index 0000000000..f3d41e573e
--- /dev/null
+++ b/test/functional/listsinceblock.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+# 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.
+"""Test the listsincelast RPC."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+class ListSinceBlockTest (BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
+
+ def run_test (self):
+ '''
+ `listsinceblock` did not behave correctly when handed a block that was
+ no longer in the main chain:
+
+ ab0
+ / \
+ aa1 [tx0] bb1
+ | |
+ aa2 bb2
+ | |
+ aa3 bb3
+ |
+ bb4
+
+ Consider a client that has only seen block `aa3` above. It asks the node
+ to `listsinceblock aa3`. But at some point prior the main chain switched
+ to the bb chain.
+
+ Previously: listsinceblock would find height=4 for block aa3 and compare
+ this to height=5 for the tip of the chain (bb4). It would then return
+ results restricted to bb3-bb4.
+
+ Now: listsinceblock finds the fork at ab0 and returns results in the
+ range bb1-bb4.
+
+ This test only checks that [tx0] is present.
+ '''
+
+ self.nodes[2].generate(101)
+ self.sync_all()
+
+ assert_equal(self.nodes[0].getbalance(), 0)
+ assert_equal(self.nodes[1].getbalance(), 0)
+ assert_equal(self.nodes[2].getbalance(), 50)
+ assert_equal(self.nodes[3].getbalance(), 0)
+
+ # Split network into two
+ self.split_network()
+
+ # send to nodes[0] from nodes[2]
+ senttx = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+
+ # generate on both sides
+ lastblockhash = self.nodes[1].generate(6)[5]
+ self.nodes[2].generate(7)
+ self.log.info('lastblockhash=%s' % (lastblockhash))
+
+ self.sync_all([self.nodes[:2], self.nodes[2:]])
+
+ self.join_network()
+
+ # listsinceblock(lastblockhash) should now include tx, as seen from nodes[0]
+ lsbres = self.nodes[0].listsinceblock(lastblockhash)
+ found = False
+ for tx in lsbres['transactions']:
+ if tx['txid'] == senttx:
+ found = True
+ break
+ assert_equal(found, True)
+
+if __name__ == '__main__':
+ ListSinceBlockTest().main()
diff --git a/qa/rpc-tests/listtransactions.py b/test/functional/listtransactions.py
index 5ec6ce17e0..cba370d8b0 100755
--- a/qa/rpc-tests/listtransactions.py
+++ b/test/functional/listtransactions.py
@@ -2,8 +2,7 @@
# Copyright (c) 2014-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.
-
-# Exercise the listtransactions API
+"""Test the listtransactions API."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -25,7 +24,7 @@ class ListTransactionsTest(BitcoinTestFramework):
def setup_nodes(self):
#This test requires mocktime
enable_mocktime()
- return start_nodes(self.num_nodes, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
# Simple send, 0 to 1:
@@ -127,7 +126,11 @@ class ListTransactionsTest(BitcoinTestFramework):
assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_1}, {"bip125-replaceable":"no"})
# Tx2 will build off txid_1, still not opting in to RBF.
+ utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_1)
+ assert_equal(utxo_to_use["safe"], True)
+ utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1)
utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1)
+ assert_equal(utxo_to_use["safe"], False)
# Create tx2 using createrawtransaction
inputs = [{"txid":utxo_to_use["txid"], "vout":utxo_to_use["vout"]}]
diff --git a/qa/rpc-tests/maxuploadtarget.py b/test/functional/maxuploadtarget.py
index 125d4eb275..bff1b53234 100755
--- a/qa/rpc-tests/maxuploadtarget.py
+++ b/test/functional/maxuploadtarget.py
@@ -2,127 +2,43 @@
# Copyright (c) 2015-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 test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-import time
-
-'''
-Test behavior of -maxuploadtarget.
+"""Test behavior of -maxuploadtarget.
* Verify that getdata requests for old blocks (>1week) are dropped
if uploadtarget has been reached.
* Verify that getdata requests for recent blocks are respecteved even
if uploadtarget has been reached.
* Verify that the upload counters are reset after 24 hours.
-'''
+"""
+from collections import defaultdict
+import time
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
-# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending
-# p2p messages to a node, generating the messages in the main testing logic.
class TestNode(NodeConnCB):
def __init__(self):
- NodeConnCB.__init__(self)
- self.connection = None
- self.ping_counter = 1
- self.last_pong = msg_pong()
- self.block_receive_map = {}
-
- def add_connection(self, conn):
- self.connection = conn
- self.peer_disconnected = False
+ super().__init__()
+ self.block_receive_map = defaultdict(int)
def on_inv(self, conn, message):
pass
- # Track the last getdata message we receive (used in the test)
- def on_getdata(self, conn, message):
- self.last_getdata = message
-
def on_block(self, conn, message):
message.block.calc_sha256()
- try:
- self.block_receive_map[message.block.sha256] += 1
- except KeyError as e:
- self.block_receive_map[message.block.sha256] = 1
-
- # Spin until verack message is received from the node.
- # We use this to signal that our test can begin. This
- # is called from the testing thread, so it needs to acquire
- # the global lock.
- def wait_for_verack(self):
- def veracked():
- return self.verack_received
- return wait_until(veracked, timeout=10)
-
- def wait_for_disconnect(self):
- def disconnected():
- return self.peer_disconnected
- return wait_until(disconnected, timeout=10)
-
- # Wrapper for the NodeConn's send_message function
- def send_message(self, message):
- self.connection.send_message(message)
-
- def on_pong(self, conn, message):
- self.last_pong = message
-
- def on_close(self, conn):
- self.peer_disconnected = True
-
- # Sync up with the node after delivery of a block
- def sync_with_ping(self, timeout=30):
- def received_pong():
- return (self.last_pong.nonce == self.ping_counter)
- self.connection.send_message(msg_ping(nonce=self.ping_counter))
- success = wait_until(received_pong, timeout)
- self.ping_counter += 1
- return success
+ self.block_receive_map[message.block.sha256] += 1
class MaxUploadTest(BitcoinTestFramework):
- def add_options(self, parser):
- parser.add_option("--testbinary", dest="testbinary",
- default=os.getenv("BITCOIND", "bitcoind"),
- help="bitcoind binary to test")
-
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
+ self.extra_args = [["-maxuploadtarget=800", "-blockmaxsize=999000"]]
- self.utxo = []
- self.txouts = gen_return_txouts()
-
- def setup_network(self):
- # Start a node with maxuploadtarget of 200 MB (/24h)
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-maxuploadtarget=800", "-blockmaxsize=999000"]))
-
- def mine_full_block(self, node, address):
- # Want to create a full block
- # We'll generate a 66k transaction below, and 14 of them is close to the 1MB block limit
- for j in range(14):
- if len(self.utxo) < 14:
- self.utxo = node.listunspent()
- inputs=[]
- outputs = {}
- t = self.utxo.pop()
- inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
- remchange = t["amount"] - Decimal("0.001000")
- outputs[address]=remchange
- # Create a basic transaction that will send change back to ourself after account for a fee
- # And then insert the 128 generated transaction outs in the middle rawtx[92] is where the #
- # of txouts is stored and is the only thing we overwrite from the original transaction
- rawtx = node.createrawtransaction(inputs, outputs)
- newtx = rawtx[0:92]
- newtx = newtx + self.txouts
- newtx = newtx + rawtx[94:]
- # Appears to be ever so slightly faster to sign with SIGHASH_NONE
- signresult = node.signrawtransaction(newtx,None,None,"NONE")
- txid = node.sendrawtransaction(signresult["hex"], True)
- # Mine a full sized block which will be these transactions we just created
- node.generate(1)
+ # Cache for utxos, as the listunspent may take a long time later in the test
+ self.utxo_cache = []
def run_test(self):
# Before we connect anything, we first set the time on the node
@@ -151,7 +67,7 @@ class MaxUploadTest(BitcoinTestFramework):
# Test logic begins here
# Now mine a big block
- self.mine_full_block(self.nodes[0], self.nodes[0].getnewaddress())
+ mine_large_block(self.nodes[0], self.utxo_cache)
# Store the hash; we'll request this later
big_old_block = self.nodes[0].getbestblockhash()
@@ -162,11 +78,10 @@ class MaxUploadTest(BitcoinTestFramework):
self.nodes[0].setmocktime(int(time.time()) - 2*60*60*24)
# Mine one more block, so that the prior block looks old
- self.mine_full_block(self.nodes[0], self.nodes[0].getnewaddress())
+ mine_large_block(self.nodes[0], self.utxo_cache)
# We'll be requesting this new block too
big_new_block = self.nodes[0].getbestblockhash()
- new_block_size = self.nodes[0].getblock(big_new_block)['size']
big_new_block = int(big_new_block, 16)
# test_nodes[0] will test what happens if we just keep requesting the
@@ -194,7 +109,7 @@ class MaxUploadTest(BitcoinTestFramework):
test_nodes[0].send_message(getdata_request)
test_nodes[0].wait_for_disconnect()
assert_equal(len(self.nodes[0].getpeerinfo()), 2)
- print("Peer 0 disconnected after downloading old block too many times")
+ self.log.info("Peer 0 disconnected after downloading old block too many times")
# Requesting the current block on test_nodes[1] should succeed indefinitely,
# even when over the max upload target.
@@ -205,7 +120,7 @@ class MaxUploadTest(BitcoinTestFramework):
test_nodes[1].sync_with_ping()
assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1)
- print("Peer 1 able to repeatedly download new block")
+ self.log.info("Peer 1 able to repeatedly download new block")
# But if test_nodes[1] tries for an old block, it gets disconnected too.
getdata_request.inv = [CInv(2, big_old_block)]
@@ -213,9 +128,9 @@ class MaxUploadTest(BitcoinTestFramework):
test_nodes[1].wait_for_disconnect()
assert_equal(len(self.nodes[0].getpeerinfo()), 1)
- print("Peer 1 disconnected after trying to download old block")
+ self.log.info("Peer 1 disconnected after trying to download old block")
- print("Advancing system time on node to clear counters...")
+ self.log.info("Advancing system time on node to clear counters...")
# If we advance the time by 24 hours, then the counters should reset,
# and test_nodes[2] should be able to retrieve the old block.
@@ -225,42 +140,35 @@ class MaxUploadTest(BitcoinTestFramework):
test_nodes[2].sync_with_ping()
assert_equal(test_nodes[2].block_receive_map[big_old_block], 1)
- print("Peer 2 able to download old block")
+ self.log.info("Peer 2 able to download old block")
[c.disconnect_node() for c in connections]
#stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1
- print("Restarting nodes with -whitelist=127.0.0.1")
+ self.log.info("Restarting nodes with -whitelist=127.0.0.1")
stop_node(self.nodes[0], 0)
- self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"])
-
- #recreate/reconnect 3 test nodes
- test_nodes = []
- connections = []
+ self.nodes[0] = start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"])
- for i in range(3):
- test_nodes.append(TestNode())
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[i]))
- test_nodes[i].add_connection(connections[i])
+ #recreate/reconnect a test node
+ test_nodes = [TestNode()]
+ connections = [NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[0])]
+ test_nodes[0].add_connection(connections[0])
NetworkThread().start() # Start up network handling in another thread
- [x.wait_for_verack() for x in test_nodes]
+ test_nodes[0].wait_for_verack()
#retrieve 20 blocks which should be enough to break the 1MB limit
getdata_request.inv = [CInv(2, big_new_block)]
for i in range(20):
- test_nodes[1].send_message(getdata_request)
- test_nodes[1].sync_with_ping()
- assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1)
+ test_nodes[0].send_message(getdata_request)
+ test_nodes[0].sync_with_ping()
+ assert_equal(test_nodes[0].block_receive_map[big_new_block], i+1)
getdata_request.inv = [CInv(2, big_old_block)]
- test_nodes[1].send_message(getdata_request)
- test_nodes[1].wait_for_disconnect()
- assert_equal(len(self.nodes[0].getpeerinfo()), 3) #node is still connected because of the whitelist
+ test_nodes[0].send_and_ping(getdata_request)
+ assert_equal(len(self.nodes[0].getpeerinfo()), 1) #node is still connected because of the whitelist
- print("Peer 1 still connected after trying to download old block (whitelisted)")
-
- [c.disconnect_node() for c in connections]
+ self.log.info("Peer still connected after trying to download old block (whitelisted)")
if __name__ == '__main__':
MaxUploadTest().main()
diff --git a/qa/rpc-tests/mempool_limit.py b/test/functional/mempool_limit.py
index 4438c152df..2777291dd0 100755
--- a/qa/rpc-tests/mempool_limit.py
+++ b/test/functional/mempool_limit.py
@@ -2,38 +2,32 @@
# Copyright (c) 2014-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.
-
-# Test mempool limiting together/eviction with the wallet
+"""Test mempool limiting together/eviction with the wallet."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class MempoolLimitTest(BitcoinTestFramework):
- def setup_network(self):
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0", "-debug"]))
- self.is_network_split = False
- self.sync_all()
- self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
-
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
-
- self.txouts = gen_return_txouts()
+ self.extra_args = [["-maxmempool=5", "-spendzeroconfchange=0"]]
def run_test(self):
+ txouts = gen_return_txouts()
+ relayfee = self.nodes[0].getnetworkinfo()['relayfee']
+
txids = []
- utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], 90)
+ utxos = create_confirmed_utxos(relayfee, self.nodes[0], 91)
#create a mempool tx that will be evicted
us0 = utxos.pop()
inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}]
outputs = {self.nodes[0].getnewaddress() : 0.0001}
tx = self.nodes[0].createrawtransaction(inputs, outputs)
- self.nodes[0].settxfee(self.relayfee) # specifically fund this tx with low fee
+ self.nodes[0].settxfee(relayfee) # specifically fund this tx with low fee
txF = self.nodes[0].fundrawtransaction(tx)
self.nodes[0].settxfee(0) # return to automatic fee selection
txFS = self.nodes[0].signrawtransaction(txF['hex'])
@@ -41,9 +35,9 @@ class MempoolLimitTest(BitcoinTestFramework):
relayfee = self.nodes[0].getnetworkinfo()['relayfee']
base_fee = relayfee*100
- for i in range (4):
+ for i in range (3):
txids.append([])
- txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[30*i:30*i+30], (i+1)*base_fee)
+ txids[i] = create_lots_of_big_transactions(self.nodes[0], txouts, utxos[30*i:30*i+30], 30, (i+1)*base_fee)
# by now, the tx should be evicted, check confirmation state
assert(txid not in self.nodes[0].getrawmempool())
diff --git a/qa/rpc-tests/mempool_packages.py b/test/functional/mempool_packages.py
index 45dc0e65c4..72f04095f4 100755
--- a/qa/rpc-tests/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -2,8 +2,7 @@
# Copyright (c) 2014-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.
-
-# Test descendant package tracking code
+"""Test descendant package tracking code."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -17,14 +16,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = False
-
- def setup_network(self):
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-relaypriority=0", "-debug"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-maxorphantx=1000", "-relaypriority=0", "-limitancestorcount=5", "-debug"]))
- connect_nodes(self.nodes[0], 1)
- self.is_network_split = False
- self.sync_all()
+ self.extra_args = [["-maxorphantx=1000"], ["-maxorphantx=1000", "-limitancestorcount=5"]]
# Build a transaction that spends parent_txid:vout
# Return amount sent
@@ -102,9 +94,21 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(mempool[x], v_descendants[x])
assert(chain[0] not in v_descendants.keys())
+ # Check that ancestor modified fees includes fee deltas from
+ # prioritisetransaction
+ self.nodes[0].prioritisetransaction(chain[0], 1000)
+ mempool = self.nodes[0].getrawmempool(True)
+ ancestor_fees = 0
+ for x in chain:
+ ancestor_fees += mempool[x]['fee']
+ assert_equal(mempool[x]['ancestorfees'], ancestor_fees * COIN + 1000)
+
+ # Undo the prioritisetransaction for later tests
+ self.nodes[0].prioritisetransaction(chain[0], -1000)
+
# Check that descendant modified fees includes fee deltas from
# prioritisetransaction
- self.nodes[0].prioritisetransaction(chain[-1], 0, 1000)
+ self.nodes[0].prioritisetransaction(chain[-1], 1000)
mempool = self.nodes[0].getrawmempool(True)
descendant_fees = 0
@@ -113,10 +117,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 1000)
# Adding one more transaction on to the chain should fail.
- try:
- self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1)
- except JSONRPCException as e:
- print("too-long-ancestor-chain successfully rejected")
+ assert_raises_jsonrpc(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], txid, vout, value, fee, 1)
# Check that prioritising a tx before it's added to the mempool works
# First clear the mempool by mining a block.
@@ -125,7 +126,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(len(self.nodes[0].getrawmempool()), 0)
# Prioritise a transaction that has been mined, then add it back to the
# mempool by using invalidateblock.
- self.nodes[0].prioritisetransaction(chain[-1], 0, 2000)
+ self.nodes[0].prioritisetransaction(chain[-1], 2000)
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# Keep node1's tip synced with node0
self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())
@@ -156,19 +157,19 @@ class MempoolPackagesTest(BitcoinTestFramework):
for i in range(10):
transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value})
- for i in range(MAX_DESCENDANTS):
+ # Sign and send up to MAX_DESCENDANT transactions chained off the parent tx
+ for i in range(MAX_DESCENDANTS - 1):
utxo = transaction_package.pop(0)
- try:
- (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
- for j in range(10):
- transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value})
- if i == MAX_DESCENDANTS - 2:
- mempool = self.nodes[0].getrawmempool(True)
- assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS)
- except JSONRPCException as e:
- print(e.error['message'])
- assert_equal(i, MAX_DESCENDANTS - 1)
- print("tx that would create too large descendant package successfully rejected")
+ (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
+ for j in range(10):
+ transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value})
+
+ mempool = self.nodes[0].getrawmempool(True)
+ assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS)
+
+ # Sending one more chained transaction will fail
+ utxo = transaction_package.pop(0)
+ assert_raises_jsonrpc(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
# TODO: check that node1's mempool is as expected
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py
new file mode 100755
index 0000000000..7b15476ea2
--- /dev/null
+++ b/test/functional/mempool_persist.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+"""Test mempool persistence.
+
+By default, bitcoind will dump mempool on shutdown and
+then reload it on startup. This can be overridden with
+the -persistmempool=0 command line option.
+
+Test is as follows:
+
+ - start node0, node1 and node2. node1 has -persistmempool=0
+ - create 5 transactions on node2 to its own address. Note that these
+ are not sent to node0 or node1 addresses because we don't want
+ them to be saved in the wallet.
+ - check that node0 and node1 have 5 transactions in their mempools
+ - shutdown all nodes.
+ - startup node0. Verify that it still has 5 transactions
+ in its mempool. Shutdown node0. This tests that by default the
+ mempool is persistent.
+ - startup node1. Verify that its mempool is empty. Shutdown node1.
+ This tests that with -persistmempool=0, the mempool is not
+ dumped to disk when the node is shut down.
+ - Restart node0 with -persistmempool=0. Verify that its mempool is
+ empty. Shutdown node0. This tests that with -persistmempool=0,
+ the mempool is not loaded from disk on start up.
+ - Restart node0 with -persistmempool. Verify that it has 5
+ transactions in its mempool. This tests that -persistmempool=0
+ does not overwrite a previously valid mempool stored on disk.
+
+"""
+import time
+
+from test_framework.mininode import wait_until
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+class MempoolPersistTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ # We need 3 nodes for this test. Node1 does not have a persistent mempool.
+ self.num_nodes = 3
+ self.setup_clean_chain = False
+ self.extra_args = [[], ["-persistmempool=0"], []]
+
+ def run_test(self):
+ chain_height = self.nodes[0].getblockcount()
+ assert_equal(chain_height, 200)
+
+ self.log.debug("Mine a single block to get out of IBD")
+ self.nodes[0].generate(1)
+ self.sync_all()
+
+ self.log.debug("Send 5 transactions from node2 (to its own address)")
+ for i in range(5):
+ self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), Decimal("10"))
+ self.sync_all()
+
+ self.log.debug("Verify that node0 and node1 have 5 transactions in their mempools")
+ assert_equal(len(self.nodes[0].getrawmempool()), 5)
+ assert_equal(len(self.nodes[1].getrawmempool()), 5)
+
+ self.log.debug("Stop-start node0 and node1. Verify that node0 has the transactions in its mempool and node1 does not.")
+ stop_nodes(self.nodes)
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir))
+ self.nodes.append(start_node(1, self.options.tmpdir))
+ # Give bitcoind a second to reload the mempool
+ time.sleep(1)
+ assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
+ assert_equal(len(self.nodes[1].getrawmempool()), 0)
+
+ self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.")
+ stop_nodes(self.nodes)
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-persistmempool=0"]))
+ # Give bitcoind a second to reload the mempool
+ time.sleep(1)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
+
+ self.log.debug("Stop-start node0. Verify that it has the transactions in its mempool.")
+ stop_nodes(self.nodes)
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir))
+ assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
+
+if __name__ == '__main__':
+ MempoolPersistTest().main()
diff --git a/qa/rpc-tests/mempool_reorg.py b/test/functional/mempool_reorg.py
index 301b094eb0..937bf4bab5 100755
--- a/qa/rpc-tests/mempool_reorg.py
+++ b/test/functional/mempool_reorg.py
@@ -2,11 +2,11 @@
# Copyright (c) 2014-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.
+"""Test mempool re-org scenarios.
-#
-# Test re-org scenarios with a mempool that contains transactions
-# that spend (directly or indirectly) coinbase transactions.
-#
+Test re-org scenarios with a mempool that contains transactions
+that spend (directly or indirectly) coinbase transactions.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -17,22 +17,15 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = False
+ self.extra_args = [["-checkmempool"]] * 2
alert_filename = None # Set by setup_network
- def setup_network(self):
- args = ["-checkmempool", "-debug=mempool"]
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, args))
- self.nodes.append(start_node(1, self.options.tmpdir, args))
- connect_nodes(self.nodes[1], 0)
- self.is_network_split = False
- self.sync_all()
-
def run_test(self):
- start_count = self.nodes[0].getblockcount()
+ # Start with a 200 block chain
+ assert_equal(self.nodes[0].getblockcount(), 200)
- # Mine three blocks. After this, nodes[0] blocks
+ # Mine four blocks. After this, nodes[0] blocks
# 101, 102, and 103 are spend-able.
new_blocks = self.nodes[1].generate(4)
self.sync_all()
@@ -52,19 +45,21 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
spend_102_raw = create_tx(self.nodes[0], coinbase_txids[2], node0_address, 49.99)
spend_103_raw = create_tx(self.nodes[0], coinbase_txids[3], node0_address, 49.99)
- # Create a block-height-locked transaction which will be invalid after reorg
+ # Create a transaction which is time-locked to two blocks in the future
timelock_tx = self.nodes[0].createrawtransaction([{"txid": coinbase_txids[0], "vout": 0}], {node0_address: 49.99})
# Set the time lock
- timelock_tx = timelock_tx.replace("ffffffff", "11111111", 1)
+ timelock_tx = timelock_tx.replace("ffffffff", "11111191", 1)
timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + "000000"
timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)["hex"]
- assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx)
+ # This will raise an exception because the timelock transaction is too immature to spend
+ assert_raises_jsonrpc(-26, "non-final", self.nodes[0].sendrawtransaction, timelock_tx)
# Broadcast and mine spend_102 and 103:
spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw)
spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)
self.nodes[0].generate(1)
- assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx)
+ # Time-locked transaction is still too immature to spend
+ assert_raises_jsonrpc(-26,'non-final', self.nodes[0].sendrawtransaction, timelock_tx)
# Create 102_1 and 103_1:
spend_102_1_raw = create_tx(self.nodes[0], spend_102_id, node1_address, 49.98)
@@ -73,6 +68,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
# Broadcast and mine 103_1:
spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)
last_block = self.nodes[0].generate(1)
+ # Time-locked transaction can now be spent
timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx)
# ... now put spend_101 and spend_102_1 in memory pools:
@@ -85,6 +81,8 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
for node in self.nodes:
node.invalidateblock(last_block[0])
+ # Time-locked transaction is now too immature and has been removed from the mempool
+ # spend_103_1 has been re-orged out of the chain and is back in the mempool
assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, spend_103_1_id})
# Use invalidateblock to re-org back and make all those coinbase spends
diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/test/functional/mempool_resurrect_test.py
index 3db12cbf76..a2f6228df9 100755
--- a/qa/rpc-tests/mempool_resurrect_test.py
+++ b/test/functional/mempool_resurrect_test.py
@@ -2,11 +2,7 @@
# Copyright (c) 2014-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.
-
-#
-# Test resurrection of mined transactions when
-# the blockchain is re-organized.
-#
+"""Test resurrection of mined transactions when the blockchain is re-organized."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -18,13 +14,8 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
super().__init__()
self.num_nodes = 1
self.setup_clean_chain = False
-
- def setup_network(self):
# Just need one node for this test
- args = ["-checkmempool", "-debug=mempool"]
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, args))
- self.is_network_split = False
+ self.extra_args = [["-checkmempool"]]
def run_test(self):
node0_address = self.nodes[0].getnewaddress()
diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/test/functional/mempool_spendcoinbase.py
index d5e4bf52d2..277ea45ad5 100755
--- a/qa/rpc-tests/mempool_spendcoinbase.py
+++ b/test/functional/mempool_spendcoinbase.py
@@ -2,16 +2,15 @@
# Copyright (c) 2014-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.
+"""Test spending coinbase transactions.
-#
-# Test spending coinbase transactions.
-# The coinbase transaction in block N can appear in block
-# N+100... so is valid in the mempool when the best block
-# height is N+99.
-# This test makes sure coinbase spends that will be mature
-# in the next block are accepted into the memory pool,
-# but less mature coinbase spends are NOT.
-#
+The coinbase transaction in block N can appear in block
+N+100... so is valid in the mempool when the best block
+height is N+99.
+This test makes sure coinbase spends that will be mature
+in the next block are accepted into the memory pool,
+but less mature coinbase spends are NOT.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -23,13 +22,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
super().__init__()
self.num_nodes = 1
self.setup_clean_chain = False
-
- def setup_network(self):
- # Just need one node for this test
- args = ["-checkmempool", "-debug=mempool"]
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, args))
- self.is_network_split = False
+ self.extra_args = [["-checkmempool"]]
def run_test(self):
chain_height = self.nodes[0].getblockcount()
@@ -46,7 +39,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])
# coinbase at height 102 should be too immature to spend
- assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, spends_raw[1])
+ assert_raises_jsonrpc(-26,"bad-txns-premature-spend-of-coinbase", self.nodes[0].sendrawtransaction, spends_raw[1])
# mempool should have just spend_101:
assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ])
diff --git a/qa/rpc-tests/merkle_blocks.py b/test/functional/merkle_blocks.py
index b2155d7fc3..06af72ef10 100755
--- a/qa/rpc-tests/merkle_blocks.py
+++ b/test/functional/merkle_blocks.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-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.
-
-#
-# Test merkleblock fetch/validation
-#
+"""Test gettxoutproof and verifytxoutproof RPCs."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -16,24 +13,19 @@ class MerkleBlockTest(BitcoinTestFramework):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 4
+ # Nodes 0/1 are "wallet" nodes, Nodes 2/3 are used for testing
+ self.extra_args = [[], [], [], ["-txindex"]]
def setup_network(self):
- self.nodes = []
- # Nodes 0/1 are "wallet" nodes
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug"]))
- # Nodes 2/3 are used for testing
- self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"]))
- self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-txindex"]))
+ self.setup_nodes()
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[0], 2)
connect_nodes(self.nodes[0], 3)
- self.is_network_split = False
self.sync_all()
def run_test(self):
- print("Mining blocks...")
+ self.log.info("Mining blocks...")
self.nodes[0].generate(105)
self.sync_all()
diff --git a/qa/rpc-tests/multi_rpc.py b/test/functional/multi_rpc.py
index 24373b257d..6ff91a960b 100755
--- a/qa/rpc-tests/multi_rpc.py
+++ b/test/functional/multi_rpc.py
@@ -2,10 +2,7 @@
# Copyright (c) 2015-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.
-
-#
-# Test mulitple rpc user config option rpcauth
-#
+"""Test multiple RPC users."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import str_to_b64str, assert_equal
@@ -26,13 +23,10 @@ class HTTPBasicsTest (BitcoinTestFramework):
#Append rpcauth to bitcoin.conf before initialization
rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144"
rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
- with open(os.path.join(self.options.tmpdir+"/node0", "bitcoin.conf"), 'a') as f:
+ with open(os.path.join(self.options.tmpdir+"/node0", "bitcoin.conf"), 'a', encoding='utf8') as f:
f.write(rpcauth+"\n")
f.write(rpcauth2+"\n")
- def setup_network(self):
- self.nodes = self.setup_nodes()
-
def run_test(self):
##################################################
@@ -44,11 +38,9 @@ class HTTPBasicsTest (BitcoinTestFramework):
authpair = url.username + ':' + url.password
#New authpair generated via share/rpcuser tool
- rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144"
password = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM="
#Second authpair with different username
- rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
password2 = "8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI="
authpairnew = "rt:"+password
diff --git a/test/functional/net.py b/test/functional/net.py
new file mode 100755
index 0000000000..fb46064441
--- /dev/null
+++ b/test/functional/net.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+# 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.
+"""Test RPC calls related to net.
+
+Tests correspond to code in rpc/net.cpp.
+"""
+
+import time
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_jsonrpc,
+ connect_nodes_bi,
+ p2p_port,
+)
+
+
+class NetTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 2
+
+ def run_test(self):
+ self._test_connection_count()
+ self._test_getnettotals()
+ self._test_getnetworkinginfo()
+ self._test_getaddednodeinfo()
+
+ def _test_connection_count(self):
+ # connect_nodes_bi connects each node to the other
+ assert_equal(self.nodes[0].getconnectioncount(), 2)
+
+ def _test_getnettotals(self):
+ # check that getnettotals totalbytesrecv and totalbytessent
+ # are consistent with getpeerinfo
+ peer_info = self.nodes[0].getpeerinfo()
+ assert_equal(len(peer_info), 2)
+ net_totals = self.nodes[0].getnettotals()
+ assert_equal(sum([peer['bytesrecv'] for peer in peer_info]),
+ net_totals['totalbytesrecv'])
+ assert_equal(sum([peer['bytessent'] for peer in peer_info]),
+ net_totals['totalbytessent'])
+ # test getnettotals and getpeerinfo by doing a ping
+ # the bytes sent/received should change
+ # note ping and pong are 32 bytes each
+ self.nodes[0].ping()
+ time.sleep(0.1)
+ peer_info_after_ping = self.nodes[0].getpeerinfo()
+ net_totals_after_ping = self.nodes[0].getnettotals()
+ for before, after in zip(peer_info, peer_info_after_ping):
+ assert_equal(before['bytesrecv_per_msg']['pong'] + 32, after['bytesrecv_per_msg']['pong'])
+ assert_equal(before['bytessent_per_msg']['ping'] + 32, after['bytessent_per_msg']['ping'])
+ assert_equal(net_totals['totalbytesrecv'] + 32*2, net_totals_after_ping['totalbytesrecv'])
+ assert_equal(net_totals['totalbytessent'] + 32*2, net_totals_after_ping['totalbytessent'])
+
+ def _test_getnetworkinginfo(self):
+ assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
+ assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
+
+ self.nodes[0].setnetworkactive(False)
+ assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False)
+ timeout = 3
+ while self.nodes[0].getnetworkinfo()['connections'] != 0:
+ # Wait a bit for all sockets to close
+ assert timeout > 0, 'not all connections closed in time'
+ timeout -= 0.1
+ time.sleep(0.1)
+
+ self.nodes[0].setnetworkactive(True)
+ connect_nodes_bi(self.nodes, 0, 1)
+ assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
+ assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
+
+ def _test_getaddednodeinfo(self):
+ assert_equal(self.nodes[0].getaddednodeinfo(), [])
+ # add a node (node2) to node0
+ ip_port = "127.0.0.1:{}".format(p2p_port(2))
+ self.nodes[0].addnode(ip_port, 'add')
+ # check that the node has indeed been added
+ added_nodes = self.nodes[0].getaddednodeinfo(ip_port)
+ assert_equal(len(added_nodes), 1)
+ assert_equal(added_nodes[0]['addednode'], ip_port)
+ # check that a non-existant node returns an error
+ assert_raises_jsonrpc(-24, "Node has not been added",
+ self.nodes[0].getaddednodeinfo, '1.1.1.1')
+
+
+if __name__ == '__main__':
+ NetTest().main()
diff --git a/test/functional/nulldummy.py b/test/functional/nulldummy.py
new file mode 100755
index 0000000000..9717add272
--- /dev/null
+++ b/test/functional/nulldummy.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Test NULLDUMMY softfork.
+
+Connect to a single node.
+Generate 2 blocks (save the coinbases for later).
+Generate 427 more blocks.
+[Policy/Consensus] Check that NULLDUMMY compliant transactions are accepted in the 430th block.
+[Policy] Check that non-NULLDUMMY transactions are rejected before activation.
+[Consensus] Check that the new NULLDUMMY rules are not enforced on the 431st block.
+[Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block.
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+from test_framework.mininode import CTransaction, NetworkThread
+from test_framework.blocktools import create_coinbase, create_block, add_witness_commitment
+from test_framework.script import CScript
+from io import BytesIO
+import time
+
+NULLDUMMY_ERROR = "64: non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)"
+
+def trueDummy(tx):
+ scriptSig = CScript(tx.vin[0].scriptSig)
+ newscript = []
+ for i in scriptSig:
+ if (len(newscript) == 0):
+ assert(len(i) == 0)
+ newscript.append(b'\x51')
+ else:
+ newscript.append(i)
+ tx.vin[0].scriptSig = CScript(newscript)
+ tx.rehash()
+
+class NULLDUMMYTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+ self.extra_args = [['-whitelist=127.0.0.1', '-walletprematurewitness']]
+
+ def run_test(self):
+ self.address = self.nodes[0].getnewaddress()
+ self.ms_address = self.nodes[0].addmultisigaddress(1,[self.address])
+ self.wit_address = self.nodes[0].addwitnessaddress(self.address)
+ self.wit_ms_address = self.nodes[0].addwitnessaddress(self.ms_address)
+
+ NetworkThread().start() # Start up network handling in another thread
+ self.coinbase_blocks = self.nodes[0].generate(2) # Block 2
+ coinbase_txid = []
+ for i in self.coinbase_blocks:
+ coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0])
+ self.nodes[0].generate(427) # Block 429
+ self.lastblockhash = self.nodes[0].getbestblockhash()
+ self.tip = int("0x" + self.lastblockhash, 0)
+ self.lastblockheight = 429
+ self.lastblocktime = int(time.time()) + 429
+
+ self.log.info("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]")
+ test1txs = [self.create_transaction(self.nodes[0], coinbase_txid[0], self.ms_address, 49)]
+ txid1 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[0].serialize_with_witness()), True)
+ test1txs.append(self.create_transaction(self.nodes[0], txid1, self.ms_address, 48))
+ txid2 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[1].serialize_with_witness()), True)
+ test1txs.append(self.create_transaction(self.nodes[0], coinbase_txid[1], self.wit_ms_address, 49))
+ txid3 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[2].serialize_with_witness()), True)
+ self.block_submit(self.nodes[0], test1txs, False, True)
+
+ self.log.info("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation")
+ test2tx = self.create_transaction(self.nodes[0], txid2, self.ms_address, 47)
+ trueDummy(test2tx)
+ assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test2tx.serialize_with_witness()), True)
+
+ self.log.info("Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]")
+ self.block_submit(self.nodes[0], [test2tx], False, True)
+
+ self.log.info("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation")
+ test4tx = self.create_transaction(self.nodes[0], test2tx.hash, self.address, 46)
+ test6txs=[CTransaction(test4tx)]
+ trueDummy(test4tx)
+ assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test4tx.serialize_with_witness()), True)
+ self.block_submit(self.nodes[0], [test4tx])
+
+ self.log.info("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation")
+ test5tx = self.create_transaction(self.nodes[0], txid3, self.wit_address, 48)
+ test6txs.append(CTransaction(test5tx))
+ test5tx.wit.vtxinwit[0].scriptWitness.stack[0] = b'\x01'
+ assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test5tx.serialize_with_witness()), True)
+ self.block_submit(self.nodes[0], [test5tx], True)
+
+ self.log.info("Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]")
+ for i in test6txs:
+ self.nodes[0].sendrawtransaction(bytes_to_hex_str(i.serialize_with_witness()), True)
+ self.block_submit(self.nodes[0], test6txs, True, True)
+
+
+ def create_transaction(self, node, txid, to_address, amount):
+ inputs = [{ "txid" : txid, "vout" : 0}]
+ outputs = { to_address : amount }
+ rawtx = node.createrawtransaction(inputs, outputs)
+ signresult = node.signrawtransaction(rawtx)
+ tx = CTransaction()
+ f = BytesIO(hex_str_to_bytes(signresult['hex']))
+ tx.deserialize(f)
+ return tx
+
+
+ def block_submit(self, node, txs, witness = False, accept = False):
+ block = create_block(self.tip, create_coinbase(self.lastblockheight + 1), self.lastblocktime + 1)
+ block.nVersion = 4
+ for tx in txs:
+ tx.rehash()
+ block.vtx.append(tx)
+ block.hashMerkleRoot = block.calc_merkle_root()
+ witness and add_witness_commitment(block)
+ block.rehash()
+ block.solve()
+ node.submitblock(bytes_to_hex_str(block.serialize(True)))
+ if (accept):
+ assert_equal(node.getbestblockhash(), block.hash)
+ self.tip = block.sha256
+ self.lastblockhash = block.hash
+ self.lastblocktime += 1
+ self.lastblockheight += 1
+ else:
+ assert_equal(node.getbestblockhash(), self.lastblockhash)
+
+if __name__ == '__main__':
+ NULLDUMMYTest().main()
diff --git a/qa/rpc-tests/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py
index 015ec34eff..322cb767db 100755
--- a/qa/rpc-tests/p2p-acceptblock.py
+++ b/test/functional/p2p-acceptblock.py
@@ -2,15 +2,7 @@
# Copyright (c) 2015-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 test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-import time
-from test_framework.blocktools import create_block, create_coinbase
-
-'''
-AcceptBlockTest -- test processing of unrequested blocks.
+"""Test processing of unrequested blocks.
Since behavior differs when receiving unrequested blocks from whitelisted peers
versus non-whitelisted peers, this tests the behavior of both (effectively two
@@ -54,56 +46,13 @@ The test:
7. Send Node0 the missing block again.
Node0 should process and the tip should advance.
-'''
-
-# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending
-# p2p messages to a node, generating the messages in the main testing logic.
-class TestNode(NodeConnCB):
- def __init__(self):
- NodeConnCB.__init__(self)
- self.connection = None
- self.ping_counter = 1
- self.last_pong = msg_pong()
-
- def add_connection(self, conn):
- self.connection = conn
-
- # Track the last getdata message we receive (used in the test)
- def on_getdata(self, conn, message):
- self.last_getdata = message
-
- # Spin until verack message is received from the node.
- # We use this to signal that our test can begin. This
- # is called from the testing thread, so it needs to acquire
- # the global lock.
- def wait_for_verack(self):
- while True:
- with mininode_lock:
- if self.verack_received:
- return
- time.sleep(0.05)
-
- # Wrapper for the NodeConn's send_message function
- def send_message(self, message):
- self.connection.send_message(message)
-
- def on_pong(self, conn, message):
- self.last_pong = message
-
- # Sync up with the node after delivery of a block
- def sync_with_ping(self, timeout=30):
- self.connection.send_message(msg_ping(nonce=self.ping_counter))
- received_pong = False
- sleep_time = 0.05
- while not received_pong and timeout > 0:
- time.sleep(sleep_time)
- timeout -= sleep_time
- with mininode_lock:
- if self.last_pong.nonce == self.ping_counter:
- received_pong = True
- self.ping_counter += 1
- return received_pong
+"""
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+import time
+from test_framework.blocktools import create_block, create_coinbase
class AcceptBlockTest(BitcoinTestFramework):
def add_options(self, parser):
@@ -115,22 +64,18 @@ class AcceptBlockTest(BitcoinTestFramework):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 2
+ self.extra_args = [[], ["-whitelist=127.0.0.1"]]
def setup_network(self):
# Node0 will be used to test behavior of processing unrequested blocks
# from peers which are not whitelisted, while Node1 will be used for
# the whitelisted case.
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"],
- binary=self.options.testbinary))
- self.nodes.append(start_node(1, self.options.tmpdir,
- ["-debug", "-whitelist=127.0.0.1"],
- binary=self.options.testbinary))
+ self.setup_nodes()
def run_test(self):
# Setup the p2p connections and start up the network thread.
- test_node = TestNode() # connects to node0 (not whitelisted)
- white_node = TestNode() # connects to node1 (whitelisted)
+ test_node = NodeConnCB() # connects to node0 (not whitelisted)
+ white_node = NodeConnCB() # connects to node1 (whitelisted)
connections = []
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node))
@@ -162,7 +107,7 @@ class AcceptBlockTest(BitcoinTestFramework):
[ x.sync_with_ping() for x in [test_node, white_node] ]
assert_equal(self.nodes[0].getblockcount(), 2)
assert_equal(self.nodes[1].getblockcount(), 2)
- print("First height 2 block accepted by both nodes")
+ self.log.info("First height 2 block accepted by both nodes")
# 3. Send another block that builds on the original tip.
blocks_h2f = [] # Blocks at height 2 that fork off the main chain
@@ -181,7 +126,7 @@ class AcceptBlockTest(BitcoinTestFramework):
if x['hash'] == blocks_h2f[1].hash:
assert_equal(x['status'], "valid-headers")
- print("Second height 2 block accepted only from whitelisted peer")
+ self.log.info("Second height 2 block accepted only from whitelisted peer")
# 4. Now send another block that builds on the forking chain.
blocks_h3 = []
@@ -199,15 +144,12 @@ class AcceptBlockTest(BitcoinTestFramework):
assert_equal(x['status'], "headers-only")
# But this block should be accepted by node0 since it has more work.
- try:
- self.nodes[0].getblock(blocks_h3[0].hash)
- print("Unrequested more-work block accepted from non-whitelisted peer")
- except:
- raise AssertionError("Unrequested more work block was not processed")
+ self.nodes[0].getblock(blocks_h3[0].hash)
+ self.log.info("Unrequested more-work block accepted from non-whitelisted peer")
# Node1 should have accepted and reorged.
assert_equal(self.nodes[1].getblockcount(), 3)
- print("Successfully reorged to length 3 chain from whitelisted peer")
+ self.log.info("Successfully reorged to length 3 chain from whitelisted peer")
# 4b. Now mine 288 more blocks and deliver; all should be processed but
# the last (height-too-high) on node0. Node1 should process the tip if
@@ -227,26 +169,17 @@ class AcceptBlockTest(BitcoinTestFramework):
tips[j] = next_block
time.sleep(2)
- for x in all_blocks:
- try:
- self.nodes[0].getblock(x.hash)
- if x == all_blocks[287]:
- raise AssertionError("Unrequested block too far-ahead should have been ignored")
- except:
- if x == all_blocks[287]:
- print("Unrequested block too far-ahead not processed")
- else:
- raise AssertionError("Unrequested block with more work should have been accepted")
+ # Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead
+ for x in all_blocks[:-1]:
+ self.nodes[0].getblock(x.hash)
+ assert_raises_jsonrpc(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash)
headers_message.headers.pop() # Ensure the last block is unrequested
white_node.send_message(headers_message) # Send headers leading to tip
white_node.send_message(msg_block(tips[1])) # Now deliver the tip
- try:
- white_node.sync_with_ping()
- self.nodes[1].getblock(tips[1].hash)
- print("Unrequested block far ahead of tip accepted from whitelisted peer")
- except:
- raise AssertionError("Unrequested block from whitelisted peer not accepted")
+ white_node.sync_with_ping()
+ self.nodes[1].getblock(tips[1].hash)
+ self.log.info("Unrequested block far ahead of tip accepted from whitelisted peer")
# 5. Test handling of unrequested block on the node that didn't process
# Should still not be processed (even though it has a child that has more
@@ -260,30 +193,30 @@ class AcceptBlockTest(BitcoinTestFramework):
# a getdata request for this block.
test_node.sync_with_ping()
assert_equal(self.nodes[0].getblockcount(), 2)
- print("Unrequested block that would complete more-work chain was ignored")
+ self.log.info("Unrequested block that would complete more-work chain was ignored")
# 6. Try to get node to request the missing block.
# Poke the node with an inv for block at height 3 and see if that
# triggers a getdata on block 2 (it should if block 2 is missing).
with mininode_lock:
# Clear state so we can check the getdata request
- test_node.last_getdata = None
+ test_node.last_message.pop("getdata", None)
test_node.send_message(msg_inv([CInv(2, blocks_h3[0].sha256)]))
test_node.sync_with_ping()
with mininode_lock:
- getdata = test_node.last_getdata
+ getdata = test_node.last_message["getdata"]
# Check that the getdata includes the right block
assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256)
- print("Inv at tip triggered getdata for unprocessed block")
+ self.log.info("Inv at tip triggered getdata for unprocessed block")
# 7. Send the missing block for the third time (now it is requested)
test_node.send_message(msg_block(blocks_h2f[0]))
test_node.sync_with_ping()
assert_equal(self.nodes[0].getblockcount(), 290)
- print("Successfully reorged to longer chain from non-whitelisted peer")
+ self.log.info("Successfully reorged to longer chain from non-whitelisted peer")
[ c.disconnect_node() for c in connections ]
diff --git a/test/functional/p2p-compactblocks.py b/test/functional/p2p-compactblocks.py
new file mode 100755
index 0000000000..9b302120ac
--- /dev/null
+++ b/test/functional/p2p-compactblocks.py
@@ -0,0 +1,945 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Test compact blocks (BIP 152).
+
+Version 1 compact blocks are pre-segwit (txids)
+Version 2 compact blocks are post-segwit (wtxids)
+"""
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
+from test_framework.script import CScript, OP_TRUE
+
+# TestNode: A peer we use to send messages to bitcoind, and store responses.
+class TestNode(NodeConnCB):
+ def __init__(self):
+ super().__init__()
+ self.last_sendcmpct = []
+ self.block_announced = False
+ # Store the hashes of blocks we've seen announced.
+ # This is for synchronizing the p2p message traffic,
+ # so we can eg wait until a particular block is announced.
+ self.announced_blockhashes = set()
+
+ def on_sendcmpct(self, conn, message):
+ self.last_sendcmpct.append(message)
+
+ def on_cmpctblock(self, conn, message):
+ self.block_announced = True
+ self.last_message["cmpctblock"].header_and_shortids.header.calc_sha256()
+ self.announced_blockhashes.add(self.last_message["cmpctblock"].header_and_shortids.header.sha256)
+
+ def on_headers(self, conn, message):
+ self.block_announced = True
+ for x in self.last_message["headers"].headers:
+ x.calc_sha256()
+ self.announced_blockhashes.add(x.sha256)
+
+ def on_inv(self, conn, message):
+ for x in self.last_message["inv"].inv:
+ if x.type == 2:
+ self.block_announced = True
+ self.announced_blockhashes.add(x.hash)
+
+ # Requires caller to hold mininode_lock
+ def received_block_announcement(self):
+ return self.block_announced
+
+ def clear_block_announcement(self):
+ with mininode_lock:
+ self.block_announced = False
+ self.last_message.pop("inv", None)
+ self.last_message.pop("headers", None)
+ self.last_message.pop("cmpctblock", None)
+
+ def get_headers(self, locator, hashstop):
+ msg = msg_getheaders()
+ msg.locator.vHave = locator
+ msg.hashstop = hashstop
+ self.connection.send_message(msg)
+
+ def send_header_for_blocks(self, new_blocks):
+ headers_message = msg_headers()
+ headers_message.headers = [CBlockHeader(b) for b in new_blocks]
+ self.send_message(headers_message)
+
+ def request_headers_and_sync(self, locator, hashstop=0):
+ self.clear_block_announcement()
+ self.get_headers(locator, hashstop)
+ assert wait_until(self.received_block_announcement, timeout=30)
+ self.clear_block_announcement()
+
+ # Block until a block announcement for a particular block hash is
+ # received.
+ def wait_for_block_announcement(self, block_hash, timeout=30):
+ def received_hash():
+ return (block_hash in self.announced_blockhashes)
+ return wait_until(received_hash, timeout=timeout)
+
+ def send_await_disconnect(self, message, timeout=30):
+ """Sends a message to the node and wait for disconnect.
+
+ This is used when we want to send a message into the node that we expect
+ will get us disconnected, eg an invalid block."""
+ self.send_message(message)
+ success = wait_until(lambda: not self.connected, timeout=timeout)
+ if not success:
+ logger.error("send_await_disconnect failed!")
+ raise AssertionError("send_await_disconnect failed!")
+ return success
+
+class CompactBlocksTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ # Node0 = pre-segwit, node1 = segwit-aware
+ self.num_nodes = 2
+ self.extra_args = [["-bip9params=segwit:0:0"], ["-txindex"]]
+ self.utxos = []
+
+ def build_block_on_tip(self, node, segwit=False):
+ height = node.getblockcount()
+ tip = node.getbestblockhash()
+ mtp = node.getblockheader(tip)['mediantime']
+ block = create_block(int(tip, 16), create_coinbase(height + 1), mtp + 1)
+ block.nVersion = 4
+ if segwit:
+ add_witness_commitment(block)
+ block.solve()
+ return block
+
+ # Create 10 more anyone-can-spend utxo's for testing.
+ def make_utxos(self):
+ # Doesn't matter which node we use, just use node0.
+ block = self.build_block_on_tip(self.nodes[0])
+ self.test_node.send_and_ping(msg_block(block))
+ assert(int(self.nodes[0].getbestblockhash(), 16) == block.sha256)
+ self.nodes[0].generate(100)
+
+ total_value = block.vtx[0].vout[0].nValue
+ out_value = total_value // 10
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(block.vtx[0].sha256, 0), b''))
+ for i in range(10):
+ tx.vout.append(CTxOut(out_value, CScript([OP_TRUE])))
+ tx.rehash()
+
+ block2 = self.build_block_on_tip(self.nodes[0])
+ block2.vtx.append(tx)
+ block2.hashMerkleRoot = block2.calc_merkle_root()
+ block2.solve()
+ self.test_node.send_and_ping(msg_block(block2))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), block2.sha256)
+ self.utxos.extend([[tx.sha256, i, out_value] for i in range(10)])
+ return
+
+ # Test "sendcmpct" (between peers preferring the same version):
+ # - No compact block announcements unless sendcmpct is sent.
+ # - If sendcmpct is sent with version > preferred_version, the message is ignored.
+ # - If sendcmpct is sent with boolean 0, then block announcements are not
+ # made with compact blocks.
+ # - If sendcmpct is then sent with boolean 1, then new block announcements
+ # are made with compact blocks.
+ # If old_node is passed in, request compact blocks with version=preferred-1
+ # and verify that it receives block announcements via compact block.
+ def test_sendcmpct(self, node, test_node, preferred_version, old_node=None):
+ # Make sure we get a SENDCMPCT message from our peer
+ def received_sendcmpct():
+ return (len(test_node.last_sendcmpct) > 0)
+ got_message = wait_until(received_sendcmpct, timeout=30)
+ assert(received_sendcmpct())
+ assert(got_message)
+ with mininode_lock:
+ # Check that the first version received is the preferred one
+ assert_equal(test_node.last_sendcmpct[0].version, preferred_version)
+ # And that we receive versions down to 1.
+ assert_equal(test_node.last_sendcmpct[-1].version, 1)
+ test_node.last_sendcmpct = []
+
+ tip = int(node.getbestblockhash(), 16)
+
+ def check_announcement_of_new_block(node, peer, predicate):
+ peer.clear_block_announcement()
+ block_hash = int(node.generate(1)[0], 16)
+ peer.wait_for_block_announcement(block_hash, timeout=30)
+ assert(peer.block_announced)
+ assert(got_message)
+
+ with mininode_lock:
+ assert predicate(peer), (
+ "block_hash={!r}, cmpctblock={!r}, inv={!r}".format(
+ block_hash, peer.last_message.get("cmpctblock", None), peer.last_message.get("inv", None)))
+
+ # We shouldn't get any block announcements via cmpctblock yet.
+ check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
+
+ # Try one more time, this time after requesting headers.
+ test_node.request_headers_and_sync(locator=[tip])
+ check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message and "inv" in p.last_message)
+
+ # Test a few ways of using sendcmpct that should NOT
+ # result in compact block announcements.
+ # Before each test, sync the headers chain.
+ test_node.request_headers_and_sync(locator=[tip])
+
+ # Now try a SENDCMPCT message with too-high version
+ sendcmpct = msg_sendcmpct()
+ sendcmpct.version = preferred_version+1
+ sendcmpct.announce = True
+ test_node.send_and_ping(sendcmpct)
+ check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
+
+ # Headers sync before next test.
+ test_node.request_headers_and_sync(locator=[tip])
+
+ # Now try a SENDCMPCT message with valid version, but announce=False
+ sendcmpct.version = preferred_version
+ sendcmpct.announce = False
+ test_node.send_and_ping(sendcmpct)
+ check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
+
+ # Headers sync before next test.
+ test_node.request_headers_and_sync(locator=[tip])
+
+ # Finally, try a SENDCMPCT message with announce=True
+ sendcmpct.version = preferred_version
+ sendcmpct.announce = True
+ test_node.send_and_ping(sendcmpct)
+ check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
+
+ # Try one more time (no headers sync should be needed!)
+ check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
+
+ # Try one more time, after turning on sendheaders
+ test_node.send_and_ping(msg_sendheaders())
+ check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
+
+ # Try one more time, after sending a version-1, announce=false message.
+ sendcmpct.version = preferred_version-1
+ sendcmpct.announce = False
+ test_node.send_and_ping(sendcmpct)
+ check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
+
+ # Now turn off announcements
+ sendcmpct.version = preferred_version
+ sendcmpct.announce = False
+ test_node.send_and_ping(sendcmpct)
+ check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message and "headers" in p.last_message)
+
+ if old_node is not None:
+ # Verify that a peer using an older protocol version can receive
+ # announcements from this node.
+ sendcmpct.version = preferred_version-1
+ sendcmpct.announce = True
+ old_node.send_and_ping(sendcmpct)
+ # Header sync
+ old_node.request_headers_and_sync(locator=[tip])
+ check_announcement_of_new_block(node, old_node, lambda p: "cmpctblock" in p.last_message)
+
+ # This test actually causes bitcoind to (reasonably!) disconnect us, so do this last.
+ def test_invalid_cmpctblock_message(self):
+ self.nodes[0].generate(101)
+ block = self.build_block_on_tip(self.nodes[0])
+
+ cmpct_block = P2PHeaderAndShortIDs()
+ cmpct_block.header = CBlockHeader(block)
+ cmpct_block.prefilled_txn_length = 1
+ # This index will be too high
+ prefilled_txn = PrefilledTransaction(1, block.vtx[0])
+ cmpct_block.prefilled_txn = [prefilled_txn]
+ self.test_node.send_await_disconnect(msg_cmpctblock(cmpct_block))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)
+
+ # Compare the generated shortids to what we expect based on BIP 152, given
+ # bitcoind's choice of nonce.
+ def test_compactblock_construction(self, node, test_node, version, use_witness_address):
+ # Generate a bunch of transactions.
+ node.generate(101)
+ num_transactions = 25
+ address = node.getnewaddress()
+ if use_witness_address:
+ # Want at least one segwit spend, so move all funds to
+ # a witness address.
+ address = node.addwitnessaddress(address)
+ value_to_send = node.getbalance()
+ node.sendtoaddress(address, satoshi_round(value_to_send-Decimal(0.1)))
+ node.generate(1)
+
+ segwit_tx_generated = False
+ for i in range(num_transactions):
+ txid = node.sendtoaddress(address, 0.1)
+ hex_tx = node.gettransaction(txid)["hex"]
+ tx = FromHex(CTransaction(), hex_tx)
+ if not tx.wit.is_null():
+ segwit_tx_generated = True
+
+ if use_witness_address:
+ assert(segwit_tx_generated) # check that our test is not broken
+
+ # Wait until we've seen the block announcement for the resulting tip
+ tip = int(node.getbestblockhash(), 16)
+ assert(test_node.wait_for_block_announcement(tip))
+
+ # Make sure we will receive a fast-announce compact block
+ self.request_cb_announcements(test_node, node, version)
+
+ # Now mine a block, and look at the resulting compact block.
+ test_node.clear_block_announcement()
+ block_hash = int(node.generate(1)[0], 16)
+
+ # Store the raw block in our internal format.
+ block = FromHex(CBlock(), node.getblock("%02x" % block_hash, False))
+ [tx.calc_sha256() for tx in block.vtx]
+ block.rehash()
+
+ # Wait until the block was announced (via compact blocks)
+ wait_until(test_node.received_block_announcement, timeout=30)
+ assert(test_node.received_block_announcement())
+
+ # Now fetch and check the compact block
+ header_and_shortids = None
+ with mininode_lock:
+ assert("cmpctblock" in test_node.last_message)
+ # Convert the on-the-wire representation to absolute indexes
+ header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
+ self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
+
+ # Now fetch the compact block using a normal non-announce getdata
+ with mininode_lock:
+ test_node.clear_block_announcement()
+ inv = CInv(4, block_hash) # 4 == "CompactBlock"
+ test_node.send_message(msg_getdata([inv]))
+
+ wait_until(test_node.received_block_announcement, timeout=30)
+ assert(test_node.received_block_announcement())
+
+ # Now fetch and check the compact block
+ header_and_shortids = None
+ with mininode_lock:
+ assert("cmpctblock" in test_node.last_message)
+ # Convert the on-the-wire representation to absolute indexes
+ header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
+ self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
+
+ def check_compactblock_construction_from_block(self, version, header_and_shortids, block_hash, block):
+ # Check that we got the right block!
+ header_and_shortids.header.calc_sha256()
+ assert_equal(header_and_shortids.header.sha256, block_hash)
+
+ # Make sure the prefilled_txn appears to have included the coinbase
+ assert(len(header_and_shortids.prefilled_txn) >= 1)
+ assert_equal(header_and_shortids.prefilled_txn[0].index, 0)
+
+ # Check that all prefilled_txn entries match what's in the block.
+ for entry in header_and_shortids.prefilled_txn:
+ entry.tx.calc_sha256()
+ # This checks the non-witness parts of the tx agree
+ assert_equal(entry.tx.sha256, block.vtx[entry.index].sha256)
+
+ # And this checks the witness
+ wtxid = entry.tx.calc_sha256(True)
+ if version == 2:
+ assert_equal(wtxid, block.vtx[entry.index].calc_sha256(True))
+ else:
+ # Shouldn't have received a witness
+ assert(entry.tx.wit.is_null())
+
+ # Check that the cmpctblock message announced all the transactions.
+ assert_equal(len(header_and_shortids.prefilled_txn) + len(header_and_shortids.shortids), len(block.vtx))
+
+ # And now check that all the shortids are as expected as well.
+ # Determine the siphash keys to use.
+ [k0, k1] = header_and_shortids.get_siphash_keys()
+
+ index = 0
+ while index < len(block.vtx):
+ if (len(header_and_shortids.prefilled_txn) > 0 and
+ header_and_shortids.prefilled_txn[0].index == index):
+ # Already checked prefilled transactions above
+ header_and_shortids.prefilled_txn.pop(0)
+ else:
+ tx_hash = block.vtx[index].sha256
+ if version == 2:
+ tx_hash = block.vtx[index].calc_sha256(True)
+ shortid = calculate_shortid(k0, k1, tx_hash)
+ assert_equal(shortid, header_and_shortids.shortids[0])
+ header_and_shortids.shortids.pop(0)
+ index += 1
+
+ # Test that bitcoind requests compact blocks when we announce new blocks
+ # via header or inv, and that responding to getblocktxn causes the block
+ # to be successfully reconstructed.
+ # Post-segwit: upgraded nodes would only make this request of cb-version-2,
+ # NODE_WITNESS peers. Unupgraded nodes would still make this request of
+ # any cb-version-1-supporting peer.
+ def test_compactblock_requests(self, node, test_node, version, segwit):
+ # Try announcing a block with an inv or header, expect a compactblock
+ # request
+ for announce in ["inv", "header"]:
+ block = self.build_block_on_tip(node, segwit=segwit)
+ with mininode_lock:
+ test_node.last_message.pop("getdata", None)
+
+ if announce == "inv":
+ test_node.send_message(msg_inv([CInv(2, block.sha256)]))
+ success = wait_until(lambda: "getheaders" in test_node.last_message, timeout=30)
+ assert(success)
+ test_node.send_header_for_blocks([block])
+ else:
+ test_node.send_header_for_blocks([block])
+ success = wait_until(lambda: "getdata" in test_node.last_message, timeout=30)
+ assert(success)
+ assert_equal(len(test_node.last_message["getdata"].inv), 1)
+ assert_equal(test_node.last_message["getdata"].inv[0].type, 4)
+ assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
+
+ # Send back a compactblock message that omits the coinbase
+ comp_block = HeaderAndShortIDs()
+ comp_block.header = CBlockHeader(block)
+ comp_block.nonce = 0
+ [k0, k1] = comp_block.get_siphash_keys()
+ coinbase_hash = block.vtx[0].sha256
+ if version == 2:
+ coinbase_hash = block.vtx[0].calc_sha256(True)
+ comp_block.shortids = [
+ calculate_shortid(k0, k1, coinbase_hash) ]
+ test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
+ assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
+ # Expect a getblocktxn message.
+ with mininode_lock:
+ assert("getblocktxn" in test_node.last_message)
+ absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
+ assert_equal(absolute_indexes, [0]) # should be a coinbase request
+
+ # Send the coinbase, and verify that the tip advances.
+ if version == 2:
+ msg = msg_witness_blocktxn()
+ else:
+ msg = msg_blocktxn()
+ msg.block_transactions.blockhash = block.sha256
+ msg.block_transactions.transactions = [block.vtx[0]]
+ test_node.send_and_ping(msg)
+ assert_equal(int(node.getbestblockhash(), 16), block.sha256)
+
+ # Create a chain of transactions from given utxo, and add to a new block.
+ def build_block_with_transactions(self, node, utxo, num_transactions):
+ block = self.build_block_on_tip(node)
+
+ for i in range(num_transactions):
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(utxo[0], utxo[1]), b''))
+ tx.vout.append(CTxOut(utxo[2] - 1000, CScript([OP_TRUE])))
+ tx.rehash()
+ utxo = [tx.sha256, 0, tx.vout[0].nValue]
+ block.vtx.append(tx)
+
+ block.hashMerkleRoot = block.calc_merkle_root()
+ block.solve()
+ return block
+
+ # Test that we only receive getblocktxn requests for transactions that the
+ # node needs, and that responding to them causes the block to be
+ # reconstructed.
+ def test_getblocktxn_requests(self, node, test_node, version):
+ with_witness = (version==2)
+
+ def test_getblocktxn_response(compact_block, peer, expected_result):
+ msg = msg_cmpctblock(compact_block.to_p2p())
+ peer.send_and_ping(msg)
+ with mininode_lock:
+ assert("getblocktxn" in peer.last_message)
+ absolute_indexes = peer.last_message["getblocktxn"].block_txn_request.to_absolute()
+ assert_equal(absolute_indexes, expected_result)
+
+ def test_tip_after_message(node, peer, msg, tip):
+ peer.send_and_ping(msg)
+ assert_equal(int(node.getbestblockhash(), 16), tip)
+
+ # First try announcing compactblocks that won't reconstruct, and verify
+ # that we receive getblocktxn messages back.
+ utxo = self.utxos.pop(0)
+
+ block = self.build_block_with_transactions(node, utxo, 5)
+ self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
+ comp_block = HeaderAndShortIDs()
+ comp_block.initialize_from_block(block, use_witness=with_witness)
+
+ test_getblocktxn_response(comp_block, test_node, [1, 2, 3, 4, 5])
+
+ msg_bt = msg_blocktxn()
+ if with_witness:
+ msg_bt = msg_witness_blocktxn() # serialize with witnesses
+ msg_bt.block_transactions = BlockTransactions(block.sha256, block.vtx[1:])
+ test_tip_after_message(node, test_node, msg_bt, block.sha256)
+
+ utxo = self.utxos.pop(0)
+ block = self.build_block_with_transactions(node, utxo, 5)
+ self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
+
+ # Now try interspersing the prefilled transactions
+ comp_block.initialize_from_block(block, prefill_list=[0, 1, 5], use_witness=with_witness)
+ test_getblocktxn_response(comp_block, test_node, [2, 3, 4])
+ msg_bt.block_transactions = BlockTransactions(block.sha256, block.vtx[2:5])
+ test_tip_after_message(node, test_node, msg_bt, block.sha256)
+
+ # Now try giving one transaction ahead of time.
+ utxo = self.utxos.pop(0)
+ block = self.build_block_with_transactions(node, utxo, 5)
+ self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
+ test_node.send_and_ping(msg_tx(block.vtx[1]))
+ assert(block.vtx[1].hash in node.getrawmempool())
+
+ # Prefill 4 out of the 6 transactions, and verify that only the one
+ # that was not in the mempool is requested.
+ comp_block.initialize_from_block(block, prefill_list=[0, 2, 3, 4], use_witness=with_witness)
+ test_getblocktxn_response(comp_block, test_node, [5])
+
+ msg_bt.block_transactions = BlockTransactions(block.sha256, [block.vtx[5]])
+ test_tip_after_message(node, test_node, msg_bt, block.sha256)
+
+ # Now provide all transactions to the node before the block is
+ # announced and verify reconstruction happens immediately.
+ utxo = self.utxos.pop(0)
+ block = self.build_block_with_transactions(node, utxo, 10)
+ self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
+ for tx in block.vtx[1:]:
+ test_node.send_message(msg_tx(tx))
+ test_node.sync_with_ping()
+ # Make sure all transactions were accepted.
+ mempool = node.getrawmempool()
+ for tx in block.vtx[1:]:
+ assert(tx.hash in mempool)
+
+ # Clear out last request.
+ with mininode_lock:
+ test_node.last_message.pop("getblocktxn", None)
+
+ # Send compact block
+ comp_block.initialize_from_block(block, prefill_list=[0], use_witness=with_witness)
+ test_tip_after_message(node, test_node, msg_cmpctblock(comp_block.to_p2p()), block.sha256)
+ with mininode_lock:
+ # Shouldn't have gotten a request for any transaction
+ assert("getblocktxn" not in test_node.last_message)
+
+ # Incorrectly responding to a getblocktxn shouldn't cause the block to be
+ # permanently failed.
+ def test_incorrect_blocktxn_response(self, node, test_node, version):
+ if (len(self.utxos) == 0):
+ self.make_utxos()
+ utxo = self.utxos.pop(0)
+
+ block = self.build_block_with_transactions(node, utxo, 10)
+ self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
+ # Relay the first 5 transactions from the block in advance
+ for tx in block.vtx[1:6]:
+ test_node.send_message(msg_tx(tx))
+ test_node.sync_with_ping()
+ # Make sure all transactions were accepted.
+ mempool = node.getrawmempool()
+ for tx in block.vtx[1:6]:
+ assert(tx.hash in mempool)
+
+ # Send compact block
+ comp_block = HeaderAndShortIDs()
+ comp_block.initialize_from_block(block, prefill_list=[0], use_witness=(version == 2))
+ test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
+ absolute_indexes = []
+ with mininode_lock:
+ assert("getblocktxn" in test_node.last_message)
+ absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
+ assert_equal(absolute_indexes, [6, 7, 8, 9, 10])
+
+ # Now give an incorrect response.
+ # Note that it's possible for bitcoind to be smart enough to know we're
+ # lying, since it could check to see if the shortid matches what we're
+ # sending, and eg disconnect us for misbehavior. If that behavior
+ # change were made, we could just modify this test by having a
+ # different peer provide the block further down, so that we're still
+ # verifying that the block isn't marked bad permanently. This is good
+ # enough for now.
+ msg = msg_blocktxn()
+ if version==2:
+ msg = msg_witness_blocktxn()
+ msg.block_transactions = BlockTransactions(block.sha256, [block.vtx[5]] + block.vtx[7:])
+ test_node.send_and_ping(msg)
+
+ # Tip should not have updated
+ assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
+
+ # We should receive a getdata request
+ success = wait_until(lambda: "getdata" in test_node.last_message, timeout=10)
+ assert(success)
+ assert_equal(len(test_node.last_message["getdata"].inv), 1)
+ assert(test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2|MSG_WITNESS_FLAG)
+ assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
+
+ # Deliver the block
+ if version==2:
+ test_node.send_and_ping(msg_witness_block(block))
+ else:
+ test_node.send_and_ping(msg_block(block))
+ assert_equal(int(node.getbestblockhash(), 16), block.sha256)
+
+ def test_getblocktxn_handler(self, node, test_node, version):
+ # bitcoind will not send blocktxn responses for blocks whose height is
+ # more than 10 blocks deep.
+ MAX_GETBLOCKTXN_DEPTH = 10
+ chain_height = node.getblockcount()
+ current_height = chain_height
+ while (current_height >= chain_height - MAX_GETBLOCKTXN_DEPTH):
+ block_hash = node.getblockhash(current_height)
+ block = FromHex(CBlock(), node.getblock(block_hash, False))
+
+ msg = msg_getblocktxn()
+ msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [])
+ num_to_request = random.randint(1, len(block.vtx))
+ msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request)))
+ test_node.send_message(msg)
+ success = wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10)
+ assert(success)
+
+ [tx.calc_sha256() for tx in block.vtx]
+ with mininode_lock:
+ assert_equal(test_node.last_message["blocktxn"].block_transactions.blockhash, int(block_hash, 16))
+ all_indices = msg.block_txn_request.to_absolute()
+ for index in all_indices:
+ tx = test_node.last_message["blocktxn"].block_transactions.transactions.pop(0)
+ tx.calc_sha256()
+ assert_equal(tx.sha256, block.vtx[index].sha256)
+ if version == 1:
+ # Witnesses should have been stripped
+ assert(tx.wit.is_null())
+ else:
+ # Check that the witness matches
+ assert_equal(tx.calc_sha256(True), block.vtx[index].calc_sha256(True))
+ test_node.last_message.pop("blocktxn", None)
+ current_height -= 1
+
+ # Next request should send a full block response, as we're past the
+ # allowed depth for a blocktxn response.
+ block_hash = node.getblockhash(current_height)
+ msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [0])
+ with mininode_lock:
+ test_node.last_message.pop("block", None)
+ test_node.last_message.pop("blocktxn", None)
+ test_node.send_and_ping(msg)
+ with mininode_lock:
+ test_node.last_message["block"].block.calc_sha256()
+ assert_equal(test_node.last_message["block"].block.sha256, int(block_hash, 16))
+ assert "blocktxn" not in test_node.last_message
+
+ def test_compactblocks_not_at_tip(self, node, test_node):
+ # Test that requesting old compactblocks doesn't work.
+ MAX_CMPCTBLOCK_DEPTH = 5
+ new_blocks = []
+ for i in range(MAX_CMPCTBLOCK_DEPTH + 1):
+ test_node.clear_block_announcement()
+ new_blocks.append(node.generate(1)[0])
+ wait_until(test_node.received_block_announcement, timeout=30)
+
+ test_node.clear_block_announcement()
+ test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))]))
+ success = wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30)
+ assert(success)
+
+ test_node.clear_block_announcement()
+ node.generate(1)
+ wait_until(test_node.received_block_announcement, timeout=30)
+ test_node.clear_block_announcement()
+ with mininode_lock:
+ test_node.last_message.pop("block", None)
+ test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))]))
+ success = wait_until(lambda: "block" in test_node.last_message, timeout=30)
+ assert(success)
+ with mininode_lock:
+ test_node.last_message["block"].block.calc_sha256()
+ assert_equal(test_node.last_message["block"].block.sha256, int(new_blocks[0], 16))
+
+ # Generate an old compactblock, and verify that it's not accepted.
+ cur_height = node.getblockcount()
+ hashPrevBlock = int(node.getblockhash(cur_height-5), 16)
+ block = self.build_block_on_tip(node)
+ block.hashPrevBlock = hashPrevBlock
+ block.solve()
+
+ comp_block = HeaderAndShortIDs()
+ comp_block.initialize_from_block(block)
+ test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
+
+ tips = node.getchaintips()
+ found = False
+ for x in tips:
+ if x["hash"] == block.hash:
+ assert_equal(x["status"], "headers-only")
+ found = True
+ break
+ assert(found)
+
+ # Requesting this block via getblocktxn should silently fail
+ # (to avoid fingerprinting attacks).
+ msg = msg_getblocktxn()
+ msg.block_txn_request = BlockTransactionsRequest(block.sha256, [0])
+ with mininode_lock:
+ test_node.last_message.pop("blocktxn", None)
+ test_node.send_and_ping(msg)
+ with mininode_lock:
+ assert "blocktxn" not in test_node.last_message
+
+ def activate_segwit(self, node):
+ node.generate(144*3)
+ assert_equal(get_bip9_status(node, "segwit")["status"], 'active')
+
+ def test_end_to_end_block_relay(self, node, listeners):
+ utxo = self.utxos.pop(0)
+
+ block = self.build_block_with_transactions(node, utxo, 10)
+
+ [l.clear_block_announcement() for l in listeners]
+
+ # ToHex() won't serialize with witness, but this block has no witnesses
+ # anyway. TODO: repeat this test with witness tx's to a segwit node.
+ node.submitblock(ToHex(block))
+
+ for l in listeners:
+ wait_until(lambda: l.received_block_announcement(), timeout=30)
+ with mininode_lock:
+ for l in listeners:
+ assert "cmpctblock" in l.last_message
+ l.last_message["cmpctblock"].header_and_shortids.header.calc_sha256()
+ assert_equal(l.last_message["cmpctblock"].header_and_shortids.header.sha256, block.sha256)
+
+ # Test that we don't get disconnected if we relay a compact block with valid header,
+ # but invalid transactions.
+ def test_invalid_tx_in_compactblock(self, node, test_node, use_segwit):
+ assert(len(self.utxos))
+ utxo = self.utxos[0]
+
+ block = self.build_block_with_transactions(node, utxo, 5)
+ del block.vtx[3]
+ block.hashMerkleRoot = block.calc_merkle_root()
+ if use_segwit:
+ # If we're testing with segwit, also drop the coinbase witness,
+ # but include the witness commitment.
+ add_witness_commitment(block)
+ block.vtx[0].wit.vtxinwit = []
+ block.solve()
+
+ # Now send the compact block with all transactions prefilled, and
+ # verify that we don't get disconnected.
+ comp_block = HeaderAndShortIDs()
+ comp_block.initialize_from_block(block, prefill_list=[0, 1, 2, 3, 4], use_witness=use_segwit)
+ msg = msg_cmpctblock(comp_block.to_p2p())
+ test_node.send_and_ping(msg)
+
+ # Check that the tip didn't advance
+ assert(int(node.getbestblockhash(), 16) is not block.sha256)
+ test_node.sync_with_ping()
+
+ # Helper for enabling cb announcements
+ # Send the sendcmpct request and sync headers
+ def request_cb_announcements(self, peer, node, version):
+ tip = node.getbestblockhash()
+ peer.get_headers(locator=[int(tip, 16)], hashstop=0)
+
+ msg = msg_sendcmpct()
+ msg.version = version
+ msg.announce = True
+ peer.send_and_ping(msg)
+
+ def test_compactblock_reconstruction_multiple_peers(self, node, stalling_peer, delivery_peer):
+ assert(len(self.utxos))
+
+ def announce_cmpct_block(node, peer):
+ utxo = self.utxos.pop(0)
+ block = self.build_block_with_transactions(node, utxo, 5)
+
+ cmpct_block = HeaderAndShortIDs()
+ cmpct_block.initialize_from_block(block)
+ msg = msg_cmpctblock(cmpct_block.to_p2p())
+ peer.send_and_ping(msg)
+ with mininode_lock:
+ assert "getblocktxn" in peer.last_message
+ return block, cmpct_block
+
+ block, cmpct_block = announce_cmpct_block(node, stalling_peer)
+
+ for tx in block.vtx[1:]:
+ delivery_peer.send_message(msg_tx(tx))
+ delivery_peer.sync_with_ping()
+ mempool = node.getrawmempool()
+ for tx in block.vtx[1:]:
+ assert(tx.hash in mempool)
+
+ delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
+ assert_equal(int(node.getbestblockhash(), 16), block.sha256)
+
+ self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
+
+ # Now test that delivering an invalid compact block won't break relay
+
+ block, cmpct_block = announce_cmpct_block(node, stalling_peer)
+ for tx in block.vtx[1:]:
+ delivery_peer.send_message(msg_tx(tx))
+ delivery_peer.sync_with_ping()
+
+ cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [ CTxInWitness() ]
+ cmpct_block.prefilled_txn[0].tx.wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]
+
+ cmpct_block.use_witness = True
+ delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
+ assert(int(node.getbestblockhash(), 16) != block.sha256)
+
+ msg = msg_blocktxn()
+ msg.block_transactions.blockhash = block.sha256
+ msg.block_transactions.transactions = block.vtx[1:]
+ stalling_peer.send_and_ping(msg)
+ assert_equal(int(node.getbestblockhash(), 16), block.sha256)
+
+ def run_test(self):
+ # Setup the p2p connections and start up the network thread.
+ self.test_node = TestNode()
+ self.segwit_node = TestNode()
+ self.old_node = TestNode() # version 1 peer <--> segwit node
+
+ connections = []
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.test_node))
+ connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1],
+ self.segwit_node, services=NODE_NETWORK|NODE_WITNESS))
+ connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1],
+ self.old_node, services=NODE_NETWORK))
+ self.test_node.add_connection(connections[0])
+ self.segwit_node.add_connection(connections[1])
+ self.old_node.add_connection(connections[2])
+
+ NetworkThread().start() # Start up network handling in another thread
+
+ # Test logic begins here
+ self.test_node.wait_for_verack()
+
+ # We will need UTXOs to construct transactions in later tests.
+ self.make_utxos()
+
+ self.log.info("Running tests, pre-segwit activation:")
+
+ self.log.info("Testing SENDCMPCT p2p message... ")
+ self.test_sendcmpct(self.nodes[0], self.test_node, 1)
+ sync_blocks(self.nodes)
+ self.test_sendcmpct(self.nodes[1], self.segwit_node, 2, old_node=self.old_node)
+ sync_blocks(self.nodes)
+
+ self.log.info("Testing compactblock construction...")
+ self.test_compactblock_construction(self.nodes[0], self.test_node, 1, False)
+ sync_blocks(self.nodes)
+ self.test_compactblock_construction(self.nodes[1], self.segwit_node, 2, False)
+ sync_blocks(self.nodes)
+
+ self.log.info("Testing compactblock requests... ")
+ self.test_compactblock_requests(self.nodes[0], self.test_node, 1, False)
+ sync_blocks(self.nodes)
+ self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, False)
+ sync_blocks(self.nodes)
+
+ self.log.info("Testing getblocktxn requests...")
+ self.test_getblocktxn_requests(self.nodes[0], self.test_node, 1)
+ sync_blocks(self.nodes)
+ self.test_getblocktxn_requests(self.nodes[1], self.segwit_node, 2)
+ sync_blocks(self.nodes)
+
+ self.log.info("Testing getblocktxn handler...")
+ self.test_getblocktxn_handler(self.nodes[0], self.test_node, 1)
+ sync_blocks(self.nodes)
+ self.test_getblocktxn_handler(self.nodes[1], self.segwit_node, 2)
+ self.test_getblocktxn_handler(self.nodes[1], self.old_node, 1)
+ sync_blocks(self.nodes)
+
+ self.log.info("Testing compactblock requests/announcements not at chain tip...")
+ self.test_compactblocks_not_at_tip(self.nodes[0], self.test_node)
+ sync_blocks(self.nodes)
+ self.test_compactblocks_not_at_tip(self.nodes[1], self.segwit_node)
+ self.test_compactblocks_not_at_tip(self.nodes[1], self.old_node)
+ sync_blocks(self.nodes)
+
+ self.log.info("Testing handling of incorrect blocktxn responses...")
+ self.test_incorrect_blocktxn_response(self.nodes[0], self.test_node, 1)
+ sync_blocks(self.nodes)
+ self.test_incorrect_blocktxn_response(self.nodes[1], self.segwit_node, 2)
+ sync_blocks(self.nodes)
+
+ # End-to-end block relay tests
+ self.log.info("Testing end-to-end block relay...")
+ self.request_cb_announcements(self.test_node, self.nodes[0], 1)
+ self.request_cb_announcements(self.old_node, self.nodes[1], 1)
+ self.request_cb_announcements(self.segwit_node, self.nodes[1], 2)
+ self.test_end_to_end_block_relay(self.nodes[0], [self.segwit_node, self.test_node, self.old_node])
+ self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node])
+
+ self.log.info("Testing handling of invalid compact blocks...")
+ self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False)
+ self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, False)
+ self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, False)
+
+ self.log.info("Testing reconstructing compact blocks from all peers...")
+ self.test_compactblock_reconstruction_multiple_peers(self.nodes[1], self.segwit_node, self.old_node)
+ sync_blocks(self.nodes)
+
+ # Advance to segwit activation
+ self.log.info("Advancing to segwit activation")
+ self.activate_segwit(self.nodes[1])
+ self.log.info("Running tests, post-segwit activation...")
+
+ self.log.info("Testing compactblock construction...")
+ self.test_compactblock_construction(self.nodes[1], self.old_node, 1, True)
+ self.test_compactblock_construction(self.nodes[1], self.segwit_node, 2, True)
+ sync_blocks(self.nodes)
+
+ self.log.info("Testing compactblock requests (unupgraded node)... ")
+ self.test_compactblock_requests(self.nodes[0], self.test_node, 1, True)
+
+ self.log.info("Testing getblocktxn requests (unupgraded node)...")
+ self.test_getblocktxn_requests(self.nodes[0], self.test_node, 1)
+
+ # Need to manually sync node0 and node1, because post-segwit activation,
+ # node1 will not download blocks from node0.
+ self.log.info("Syncing nodes...")
+ assert(self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash())
+ while (self.nodes[0].getblockcount() > self.nodes[1].getblockcount()):
+ block_hash = self.nodes[0].getblockhash(self.nodes[1].getblockcount()+1)
+ self.nodes[1].submitblock(self.nodes[0].getblock(block_hash, False))
+ assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash())
+
+ self.log.info("Testing compactblock requests (segwit node)... ")
+ self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, True)
+
+ self.log.info("Testing getblocktxn requests (segwit node)...")
+ self.test_getblocktxn_requests(self.nodes[1], self.segwit_node, 2)
+ sync_blocks(self.nodes)
+
+ self.log.info("Testing getblocktxn handler (segwit node should return witnesses)...")
+ self.test_getblocktxn_handler(self.nodes[1], self.segwit_node, 2)
+ self.test_getblocktxn_handler(self.nodes[1], self.old_node, 1)
+
+ # Test that if we submitblock to node1, we'll get a compact block
+ # announcement to all peers.
+ # (Post-segwit activation, blocks won't propagate from node0 to node1
+ # automatically, so don't bother testing a block announced to node0.)
+ self.log.info("Testing end-to-end block relay...")
+ self.request_cb_announcements(self.test_node, self.nodes[0], 1)
+ self.request_cb_announcements(self.old_node, self.nodes[1], 1)
+ self.request_cb_announcements(self.segwit_node, self.nodes[1], 2)
+ self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node])
+
+ self.log.info("Testing handling of invalid compact blocks...")
+ self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False)
+ self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, True)
+ self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, True)
+
+ self.log.info("Testing invalid index in cmpctblock message...")
+ self.test_invalid_cmpctblock_message()
+
+
+if __name__ == '__main__':
+ CompactBlocksTest().main()
diff --git a/qa/rpc-tests/p2p-feefilter.py b/test/functional/p2p-feefilter.py
index cd0501a314..dbccb633a5 100755
--- a/qa/rpc-tests/p2p-feefilter.py
+++ b/test/functional/p2p-feefilter.py
@@ -2,16 +2,13 @@
# Copyright (c) 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.
-#
+"""Test processing of feefilter messages."""
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
import time
-'''
-FeeFilterTest -- test processing of feefilter messages
-'''
def hashToHex(hash):
return format(hash, '064x')
@@ -21,15 +18,13 @@ def allInvsMatch(invsExpected, testnode):
for x in range(60):
with mininode_lock:
if (sorted(invsExpected) == sorted(testnode.txinvs)):
- return True;
+ return True
time.sleep(1)
- return False;
+ return False
-# TestNode: bare-bones "peer". Used to track which invs are received from a node
-# and to send the node feefilter messages.
-class TestNode(SingleNodeConnCB):
+class TestNode(NodeConnCB):
def __init__(self):
- SingleNodeConnCB.__init__(self)
+ super().__init__()
self.txinvs = []
def on_inv(self, conn, message):
@@ -41,10 +36,6 @@ class TestNode(SingleNodeConnCB):
with mininode_lock:
self.txinvs = []
- def send_filter(self, feerate):
- self.send_message(msg_feefilter(feerate))
- self.sync_with_ping()
-
class FeeFilterTest(BitcoinTestFramework):
def __init__(self):
@@ -52,16 +43,9 @@ class FeeFilterTest(BitcoinTestFramework):
self.num_nodes = 2
self.setup_clean_chain = False
- def setup_network(self):
- # Node1 will be used to generate txs which should be relayed from Node0
- # to our test node
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros"]))
- connect_nodes(self.nodes[0], 1)
-
def run_test(self):
node1 = self.nodes[1]
+ node0 = self.nodes[0]
# Get out of IBD
node1.generate(1)
sync_blocks(self.nodes)
@@ -80,7 +64,7 @@ class FeeFilterTest(BitcoinTestFramework):
test_node.clear_invs()
# Set a filter of 15 sat/byte
- test_node.send_filter(15000)
+ test_node.send_and_ping(msg_feefilter(15000))
# Test that txs are still being received (paying 20 sat/byte)
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]
@@ -91,12 +75,21 @@ class FeeFilterTest(BitcoinTestFramework):
node1.settxfee(Decimal("0.00010000"))
[node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]
sync_mempools(self.nodes) # must be sure node 0 has received all txs
- time.sleep(10) # wait 10 secs to be sure its doesn't relay any
- assert(allInvsMatch([], test_node))
+
+ # Send one transaction from node0 that should be received, so that we
+ # we can sync the test on receipt (if node1's txs were relayed, they'd
+ # be received by the time this node0 tx is received). This is
+ # unfortunately reliant on the current relay behavior where we batch up
+ # to 35 entries in an inv, which means that when this next transaction
+ # is eligible for relay, the prior transactions from node1 are eligible
+ # as well.
+ node0.settxfee(Decimal("0.00020000"))
+ txids = [node0.sendtoaddress(node0.getnewaddress(), 1)]
+ assert(allInvsMatch(txids, test_node))
test_node.clear_invs()
# Remove fee filter and check that txs are received again
- test_node.send_filter(0)
+ test_node.send_and_ping(msg_feefilter(0))
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]
assert(allInvsMatch(txids, test_node))
test_node.clear_invs()
diff --git a/qa/rpc-tests/p2p-fullblocktest.py b/test/functional/p2p-fullblocktest.py
index 17fd40ef1d..e7fe7372c8 100755
--- a/qa/rpc-tests/p2p-fullblocktest.py
+++ b/test/functional/p2p-fullblocktest.py
@@ -2,6 +2,14 @@
# Copyright (c) 2015-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.
+"""Test block processing.
+
+This reimplements tests from the bitcoinj/FullBlockTestGenerator used
+by the pull-tester.
+
+We use the testing framework in which we expect a particular answer from
+each test.
+"""
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import *
@@ -17,17 +25,6 @@ class PreviousSpendableOutput(object):
self.tx = tx
self.n = n # the output we're spending
-'''
-This reimplements tests from the bitcoinj/FullBlockTestGenerator used
-by the pull-tester.
-
-We use the testing framework in which we expect a particular answer from
-each test.
-'''
-
-def hash160(s):
- return hashlib.new('ripemd160', sha256(s)).digest()
-
# Use this class for tests that require behavior other than normal "mininode" behavior.
# For now, it is used to serialize a bloated varint (b64).
class CBrokenBlock(CBlock):
@@ -354,7 +351,7 @@ class FullBlockTest(ComparisonTestFramework):
block(22, spend=out[5])
yield rejected()
- # Create a block on either side of MAX_BLOCK_SIZE and make sure its accepted/rejected
+ # Create a block on either side of MAX_BLOCK_BASE_SIZE and make sure its accepted/rejected
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
# \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6)
# \-> b24 (6) -> b25 (7)
@@ -362,24 +359,24 @@ class FullBlockTest(ComparisonTestFramework):
tip(15)
b23 = block(23, spend=out[6])
tx = CTransaction()
- script_length = MAX_BLOCK_SIZE - len(b23.serialize()) - 69
+ script_length = MAX_BLOCK_BASE_SIZE - len(b23.serialize()) - 69
script_output = CScript([b'\x00' * script_length])
tx.vout.append(CTxOut(0, script_output))
tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 0)))
b23 = update_block(23, [tx])
# Make sure the math above worked out to produce a max-sized block
- assert_equal(len(b23.serialize()), MAX_BLOCK_SIZE)
+ assert_equal(len(b23.serialize()), MAX_BLOCK_BASE_SIZE)
yield accepted()
save_spendable_output()
# Make the next block one byte bigger and check that it fails
tip(15)
b24 = block(24, spend=out[6])
- script_length = MAX_BLOCK_SIZE - len(b24.serialize()) - 69
+ script_length = MAX_BLOCK_BASE_SIZE - len(b24.serialize()) - 69
script_output = CScript([b'\x00' * (script_length+1)])
tx.vout = [CTxOut(0, script_output)]
b24 = update_block(24, [tx])
- assert_equal(len(b24.serialize()), MAX_BLOCK_SIZE+1)
+ assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE+1)
yield rejected(RejectResult(16, b'bad-blk-length'))
block(25, spend=out[7])
@@ -401,7 +398,7 @@ class FullBlockTest(ComparisonTestFramework):
# Extend the b26 chain to make sure bitcoind isn't accepting b26
b27 = block(27, spend=out[7])
- yield rejected(RejectResult(16, b'bad-prevblk'))
+ yield rejected(False)
# Now try a too-large-coinbase script
tip(15)
@@ -413,7 +410,7 @@ class FullBlockTest(ComparisonTestFramework):
# Extend the b28 chain to make sure bitcoind isn't accepting b28
b29 = block(29, spend=out[7])
- yield rejected(RejectResult(16, b'bad-prevblk'))
+ yield rejected(False)
# b30 has a max-sized coinbase scriptSig.
tip(23)
@@ -526,12 +523,12 @@ class FullBlockTest(ComparisonTestFramework):
tx_new = None
tx_last = tx
total_size=len(b39.serialize())
- while(total_size < MAX_BLOCK_SIZE):
+ while(total_size < MAX_BLOCK_BASE_SIZE):
tx_new = create_tx(tx_last, 1, 1, p2sh_script)
tx_new.vout.append(CTxOut(tx_last.vout[1].nValue - 1, CScript([OP_TRUE])))
tx_new.rehash()
total_size += len(tx_new.serialize())
- if total_size >= MAX_BLOCK_SIZE:
+ if total_size >= MAX_BLOCK_BASE_SIZE:
break
b39.vtx.append(tx_new) # add tx to block
tx_last = tx_new
@@ -880,7 +877,7 @@ class FullBlockTest(ComparisonTestFramework):
# This checks that a block with a bloated VARINT between the block_header and the array of tx such that
- # the block is > MAX_BLOCK_SIZE with the bloated varint, but <= MAX_BLOCK_SIZE without the bloated varint,
+ # the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint,
# does not cause a subsequent, identical block with canonical encoding to be rejected. The test does not
# care whether the bloated block is accepted or rejected; it only cares that the second block is accepted.
#
@@ -904,12 +901,12 @@ class FullBlockTest(ComparisonTestFramework):
tx = CTransaction()
# use canonical serialization to calculate size
- script_length = MAX_BLOCK_SIZE - len(b64a.normal_serialize()) - 69
+ script_length = MAX_BLOCK_BASE_SIZE - len(b64a.normal_serialize()) - 69
script_output = CScript([b'\x00' * script_length])
tx.vout.append(CTxOut(0, script_output))
tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))
b64a = update_block("64a", [tx])
- assert_equal(len(b64a.serialize()), MAX_BLOCK_SIZE + 8)
+ assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8)
yield TestInstance([[self.tip, None]])
# comptool workaround: to make sure b64 is delivered, manually erase b64a from blockstore
@@ -919,7 +916,7 @@ class FullBlockTest(ComparisonTestFramework):
b64 = CBlock(b64a)
b64.vtx = copy.deepcopy(b64a.vtx)
assert_equal(b64.hash, b64a.hash)
- assert_equal(len(b64.serialize()), MAX_BLOCK_SIZE)
+ assert_equal(len(b64.serialize()), MAX_BLOCK_BASE_SIZE)
self.blocks[64] = b64
update_block(64, [])
yield accepted()
@@ -1253,12 +1250,12 @@ class FullBlockTest(ComparisonTestFramework):
for i in range(89, LARGE_REORG_SIZE + 89):
b = block(i, spend)
tx = CTransaction()
- script_length = MAX_BLOCK_SIZE - len(b.serialize()) - 69
+ script_length = MAX_BLOCK_BASE_SIZE - len(b.serialize()) - 69
script_output = CScript([b'\x00' * script_length])
tx.vout.append(CTxOut(0, script_output))
tx.vin.append(CTxIn(COutPoint(b.vtx[1].sha256, 0)))
b = update_block(i, [tx])
- assert_equal(len(b.serialize()), MAX_BLOCK_SIZE)
+ assert_equal(len(b.serialize()), MAX_BLOCK_BASE_SIZE)
test1.blocks_and_transactions.append([self.tip, True])
save_spendable_output()
spend = get_spendable_output()
diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py
new file mode 100755
index 0000000000..33b57ef33d
--- /dev/null
+++ b/test/functional/p2p-leaktests.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python3
+# 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.
+"""Test message sending before handshake completion.
+
+A node should never send anything other than VERSION/VERACK/REJECT until it's
+received a VERACK.
+
+This test connects to a node and sends it a few messages, trying to intice it
+into sending us something it shouldn't.
+"""
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+banscore = 10
+
+class CLazyNode(NodeConnCB):
+ def __init__(self):
+ super().__init__()
+ self.unexpected_msg = False
+ self.ever_connected = False
+
+ def bad_message(self, message):
+ self.unexpected_msg = True
+ self.log.info("should not have received message: %s" % message.command)
+
+ def on_open(self, conn):
+ self.connected = True
+ self.ever_connected = True
+
+ def on_version(self, conn, message): self.bad_message(message)
+ def on_verack(self, conn, message): self.bad_message(message)
+ def on_reject(self, conn, message): self.bad_message(message)
+ def on_inv(self, conn, message): self.bad_message(message)
+ def on_addr(self, conn, message): self.bad_message(message)
+ def on_alert(self, conn, message): self.bad_message(message)
+ def on_getdata(self, conn, message): self.bad_message(message)
+ def on_getblocks(self, conn, message): self.bad_message(message)
+ def on_tx(self, conn, message): self.bad_message(message)
+ def on_block(self, conn, message): self.bad_message(message)
+ def on_getaddr(self, conn, message): self.bad_message(message)
+ def on_headers(self, conn, message): self.bad_message(message)
+ def on_getheaders(self, conn, message): self.bad_message(message)
+ def on_ping(self, conn, message): self.bad_message(message)
+ def on_mempool(self, conn): self.bad_message(message)
+ def on_pong(self, conn, message): self.bad_message(message)
+ def on_feefilter(self, conn, message): self.bad_message(message)
+ def on_sendheaders(self, conn, message): self.bad_message(message)
+ def on_sendcmpct(self, conn, message): self.bad_message(message)
+ def on_cmpctblock(self, conn, message): self.bad_message(message)
+ def on_getblocktxn(self, conn, message): self.bad_message(message)
+ def on_blocktxn(self, conn, message): self.bad_message(message)
+
+# Node that never sends a version. We'll use this to send a bunch of messages
+# anyway, and eventually get disconnected.
+class CNodeNoVersionBan(CLazyNode):
+ # send a bunch of veracks without sending a message. This should get us disconnected.
+ # NOTE: implementation-specific check here. Remove if bitcoind ban behavior changes
+ def on_open(self, conn):
+ super().on_open(conn)
+ for i in range(banscore):
+ self.send_message(msg_verack())
+
+ def on_reject(self, conn, message): pass
+
+# Node that never sends a version. This one just sits idle and hopes to receive
+# any message (it shouldn't!)
+class CNodeNoVersionIdle(CLazyNode):
+ def __init__(self):
+ super().__init__()
+
+# Node that sends a version but not a verack.
+class CNodeNoVerackIdle(CLazyNode):
+ def __init__(self):
+ self.version_received = False
+ super().__init__()
+
+ def on_reject(self, conn, message): pass
+ def on_verack(self, conn, message): pass
+ # When version is received, don't reply with a verack. Instead, see if the
+ # node will give us a message that it shouldn't. This is not an exhaustive
+ # list!
+ def on_version(self, conn, message):
+ self.version_received = True
+ conn.send_message(msg_ping())
+ conn.send_message(msg_getaddr())
+
+class P2PLeakTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 1
+ self.extra_args = [['-banscore='+str(banscore)]]
+
+ def run_test(self):
+ no_version_bannode = CNodeNoVersionBan()
+ no_version_idlenode = CNodeNoVersionIdle()
+ no_verack_idlenode = CNodeNoVerackIdle()
+
+ connections = []
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_bannode, send_version=False))
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_idlenode, send_version=False))
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_verack_idlenode))
+ no_version_bannode.add_connection(connections[0])
+ no_version_idlenode.add_connection(connections[1])
+ no_verack_idlenode.add_connection(connections[2])
+
+ NetworkThread().start() # Start up network handling in another thread
+
+ assert wait_until(lambda: no_version_bannode.ever_connected, timeout=10)
+ assert wait_until(lambda: no_version_idlenode.ever_connected, timeout=10)
+ assert wait_until(lambda: no_verack_idlenode.version_received, timeout=10)
+
+ # Mine a block and make sure that it's not sent to the connected nodes
+ self.nodes[0].generate(1)
+
+ #Give the node enough time to possibly leak out a message
+ time.sleep(5)
+
+ #This node should have been banned
+ assert not no_version_bannode.connected
+
+ [conn.disconnect_node() for conn in connections]
+
+ # Make sure no unexpected messages came in
+ assert(no_version_bannode.unexpected_msg == False)
+ assert(no_version_idlenode.unexpected_msg == False)
+ assert(no_verack_idlenode.unexpected_msg == False)
+
+if __name__ == '__main__':
+ P2PLeakTest().main()
diff --git a/test/functional/p2p-mempool.py b/test/functional/p2p-mempool.py
new file mode 100755
index 0000000000..34ef249eea
--- /dev/null
+++ b/test/functional/p2p-mempool.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+# Copyright (c) 2015-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.
+"""Test p2p mempool message.
+
+Test that nodes are disconnected if they send mempool messages when bloom
+filters are not enabled.
+"""
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+class P2PMempoolTests(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+ self.extra_args = [["-peerbloomfilters=0"]]
+
+ def run_test(self):
+ #connect a mininode
+ aTestNode = NodeConnCB()
+ node = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], aTestNode)
+ aTestNode.add_connection(node)
+ NetworkThread().start()
+ aTestNode.wait_for_verack()
+
+ #request mempool
+ aTestNode.send_message(msg_mempool())
+ aTestNode.wait_for_disconnect()
+
+ #mininode must be disconnected at this point
+ assert_equal(len(self.nodes[0].getpeerinfo()), 0)
+
+if __name__ == '__main__':
+ P2PMempoolTests().main()
diff --git a/qa/rpc-tests/p2p-segwit.py b/test/functional/p2p-segwit.py
index b30d41af92..24d4d37c42 100755
--- a/qa/rpc-tests/p2p-segwit.py
+++ b/test/functional/p2p-segwit.py
@@ -2,12 +2,13 @@
# Copyright (c) 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.
+"""Test segwit transactions and blocks on P2P network."""
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from test_framework.script import *
-from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, WITNESS_COMMITMENT_HEADER
+from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, get_witness_script, WITNESS_COMMITMENT_HEADER
from test_framework.key import CECKey, CPubKey
import time
import random
@@ -21,9 +22,6 @@ VB_TOP_BITS = 0x20000000
MAX_SIGOP_COST = 80000
-'''
-SegWit p2p test.
-'''
# Calculate the virtual size of a witness block:
# (base + witness/4)
@@ -34,108 +32,41 @@ def get_virtual_size(witness_block):
vsize = int((3*base_size + total_size + 3)/4)
return vsize
-# Note: we can reduce code by using SingleNodeConnCB (in master, not 0.12)
class TestNode(NodeConnCB):
def __init__(self):
- NodeConnCB.__init__(self)
- self.connection = None
- self.ping_counter = 1
- self.last_pong = msg_pong(0)
- self.sleep_time = 0.05
+ super().__init__()
self.getdataset = set()
- self.last_reject = None
-
- def add_connection(self, conn):
- self.connection = conn
-
- # Wrapper for the NodeConn's send_message function
- def send_message(self, message):
- self.connection.send_message(message)
-
- def on_inv(self, conn, message):
- self.last_inv = message
-
- def on_block(self, conn, message):
- self.last_block = message.block
- self.last_block.calc_sha256()
def on_getdata(self, conn, message):
for inv in message.inv:
self.getdataset.add(inv.hash)
- self.last_getdata = message
-
- def on_pong(self, conn, message):
- self.last_pong = message
-
- def on_reject(self, conn, message):
- self.last_reject = message
- #print (message)
-
- # Syncing helpers
- def sync(self, test_function, timeout=60):
- while timeout > 0:
- with mininode_lock:
- if test_function():
- return
- time.sleep(self.sleep_time)
- timeout -= self.sleep_time
- raise AssertionError("Sync failed to complete")
-
- def sync_with_ping(self, timeout=60):
- self.send_message(msg_ping(nonce=self.ping_counter))
- test_function = lambda: self.last_pong.nonce == self.ping_counter
- self.sync(test_function, timeout)
- self.ping_counter += 1
- return
-
- def wait_for_block(self, blockhash, timeout=60):
- test_function = lambda: self.last_block != None and self.last_block.sha256 == blockhash
- self.sync(test_function, timeout)
- return
-
- def wait_for_getdata(self, timeout=60):
- test_function = lambda: self.last_getdata != None
- self.sync(test_function, timeout)
-
- def wait_for_inv(self, expected_inv, timeout=60):
- test_function = lambda: self.last_inv != expected_inv
- self.sync(test_function, timeout)
def announce_tx_and_wait_for_getdata(self, tx, timeout=60):
with mininode_lock:
- self.last_getdata = None
+ self.last_message.pop("getdata", None)
self.send_message(msg_inv(inv=[CInv(1, tx.sha256)]))
self.wait_for_getdata(timeout)
- return
def announce_block_and_wait_for_getdata(self, block, use_header, timeout=60):
with mininode_lock:
- self.last_getdata = None
+ self.last_message.pop("getdata", None)
+ self.last_message.pop("getheaders", None)
+ msg = msg_headers()
+ msg.headers = [ CBlockHeader(block) ]
if use_header:
- msg = msg_headers()
- msg.headers = [ CBlockHeader(block) ]
self.send_message(msg)
else:
self.send_message(msg_inv(inv=[CInv(2, block.sha256)]))
- self.wait_for_getdata()
- return
-
- def announce_block(self, block, use_header):
- with mininode_lock:
- self.last_getdata = None
- if use_header:
- msg = msg_headers()
- msg.headers = [ CBlockHeader(block) ]
+ self.wait_for_getheaders()
self.send_message(msg)
- else:
- self.send_message(msg_inv(inv=[CInv(2, block.sha256)]))
+ self.wait_for_getdata()
def request_block(self, blockhash, inv_type, timeout=60):
with mininode_lock:
- self.last_block = None
+ self.last_message.pop("block", None)
self.send_message(msg_getdata(inv=[CInv(inv_type, blockhash)]))
self.wait_for_block(blockhash, timeout)
- return self.last_block
+ return self.last_message["block"].block
def test_transaction_acceptance(self, tx, with_witness, accepted, reason=None):
tx_message = msg_tx(tx)
@@ -147,7 +78,7 @@ class TestNode(NodeConnCB):
if (reason != None and not accepted):
# Check the rejection reason as well.
with mininode_lock:
- assert_equal(self.last_reject.reason, reason)
+ assert_equal(self.last_message["reject"].reason, reason)
# Test whether a witness block had the correct effect on the tip
def test_witness_block(self, block, accepted, with_witness=True):
@@ -158,7 +89,6 @@ class TestNode(NodeConnCB):
self.sync_with_ping()
assert_equal(self.connection.rpc.getbestblockhash() == block.hash, accepted)
-
# Used to keep track of anyone-can-spend outputs that we can use in the tests
class UTXO(object):
def __init__(self, sha256, n, nValue):
@@ -166,29 +96,31 @@ class UTXO(object):
self.n = n
self.nValue = nValue
+# Helper for getting the script associated with a P2PKH
+def GetP2PKHScript(pubkeyhash):
+ return CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])
+
+# Add signature for a P2PK witness program.
+def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key):
+ tx_hash = SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, value)
+ signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
+ txTo.wit.vtxinwit[inIdx].scriptWitness.stack = [signature, script]
+ txTo.rehash()
+
class SegWitTest(BitcoinTestFramework):
- def setup_chain(self):
- initialize_chain_clean(self.options.tmpdir, 3)
- def add_options(self, parser):
- parser.add_option("--oldbinary", dest="oldbinary",
- default=None,
- help="pre-segwit bitcoind binary for upgrade testing")
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+ self.extra_args = [["-whitelist=127.0.0.1"], ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0"], ["-whitelist=127.0.0.1", "-bip9params=segwit:0:0"]]
def setup_network(self):
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-whitelist=127.0.0.1"]))
- # Start a node for testing IsStandard rules.
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-whitelist=127.0.0.1", "-acceptnonstdtxn=0"]))
+ self.setup_nodes()
connect_nodes(self.nodes[0], 1)
-
- # If an old bitcoind is given, do the upgrade-after-activation test.
- self.test_upgrade = False
- if (self.options.oldbinary != None):
- self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-whitelist=127.0.0.1"], binary=self.options.oldbinary))
- connect_nodes(self.nodes[0], 2)
- self.test_upgrade = True
+ connect_nodes(self.nodes[0], 2)
+ self.sync_all()
''' Helpers '''
# Build a block on top of node0's tip.
@@ -210,7 +142,7 @@ class SegWitTest(BitcoinTestFramework):
''' Individual tests '''
def test_witness_services(self):
- print("\tVerifying NODE_WITNESS service bit")
+ self.log.info("Verifying NODE_WITNESS service bit")
assert((self.test_node.connection.nServices & NODE_WITNESS) != 0)
@@ -219,7 +151,7 @@ class SegWitTest(BitcoinTestFramework):
def test_non_witness_transaction(self):
# Mine a block with an anyone-can-spend coinbase,
# let it mature, then try to spend it.
- print("\tTesting non-witness transaction")
+ self.log.info("Testing non-witness transaction")
block = self.build_next_block(nVersion=1)
block.solve()
self.test_node.send_message(msg_block(block))
@@ -248,7 +180,7 @@ class SegWitTest(BitcoinTestFramework):
# Verify that blocks with witnesses are rejected before activation.
def test_unnecessary_witness_before_segwit_activation(self):
- print("\tTesting behavior of unnecessary witnesses")
+ self.log.info("Testing behavior of unnecessary witnesses")
# For now, rely on earlier tests to have created at least one utxo for
# us to use
assert(len(self.utxo) > 0)
@@ -274,7 +206,7 @@ class SegWitTest(BitcoinTestFramework):
# TODO: fix synchronization so we can test reject reason
# Right now, bitcoind delays sending reject messages for blocks
# until the future, making synchronization here difficult.
- #assert_equal(self.test_node.last_reject.reason, "unexpected-witness")
+ #assert_equal(self.test_node.last_message["reject"].reason, "unexpected-witness")
# But it should not be permanently marked bad...
# Resend without witness information.
@@ -302,13 +234,18 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
# We'll add an unnecessary witness to this transaction that would cause
- # it to be too large according to IsStandard.
+ # it to be non-standard, to test that violating policy with a witness before
+ # segwit activation doesn't blind a node to a transaction. Transactions
+ # rejected for having a witness before segwit activation shouldn't be added
+ # to the rejection cache.
tx3 = CTransaction()
tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), CScript([p2sh_program])))
tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, scriptPubKey))
tx3.wit.vtxinwit.append(CTxInWitness())
tx3.wit.vtxinwit[0].scriptWitness.stack = [b'a'*400000]
tx3.rehash()
+ # Note that this should be rejected for the premature witness reason,
+ # rather than a policy check, since segwit hasn't activated yet.
self.std_node.test_transaction_acceptance(tx3, True, False, b'no-witness-yet')
# If we send without witness, it should be accepted.
@@ -370,7 +307,7 @@ class SegWitTest(BitcoinTestFramework):
# This test can only be run after segwit has activated
def test_witness_commitments(self):
- print("\tTesting witness commitments")
+ self.log.info("Testing witness commitments")
# First try a correct witness commitment.
block = self.build_next_block()
@@ -459,7 +396,7 @@ class SegWitTest(BitcoinTestFramework):
def test_block_malleability(self):
- print("\tTesting witness block malleability")
+ self.log.info("Testing witness block malleability")
# Make sure that a block that has too big a virtual size
# because of a too-large coinbase witness is not permanently
@@ -469,7 +406,7 @@ class SegWitTest(BitcoinTestFramework):
block.solve()
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.append(b'a'*5000000)
- assert(get_virtual_size(block) > MAX_BLOCK_SIZE)
+ assert(get_virtual_size(block) > MAX_BLOCK_BASE_SIZE)
# We can't send over the p2p network, because this is too big to relay
# TODO: repeat this test with a block that can be relayed
@@ -478,7 +415,7 @@ class SegWitTest(BitcoinTestFramework):
assert(self.nodes[0].getbestblockhash() != block.hash)
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.pop()
- assert(get_virtual_size(block) < MAX_BLOCK_SIZE)
+ assert(get_virtual_size(block) < MAX_BLOCK_BASE_SIZE)
self.nodes[0].submitblock(bytes_to_hex_str(block.serialize(True)))
assert(self.nodes[0].getbestblockhash() == block.hash)
@@ -500,7 +437,7 @@ class SegWitTest(BitcoinTestFramework):
def test_witness_block_size(self):
- print("\tTesting witness block size limit")
+ self.log.info("Testing witness block size limit")
# TODO: Test that non-witness carrying blocks can't exceed 1MB
# Skipping this test for now; this is covered in p2p-fullblocktest.py
@@ -543,10 +480,10 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [parent_tx, child_tx])
vsize = get_virtual_size(block)
- additional_bytes = (MAX_BLOCK_SIZE - vsize)*4
+ additional_bytes = (MAX_BLOCK_BASE_SIZE - vsize)*4
i = 0
while additional_bytes > 0:
- # Add some more bytes to each input until we hit MAX_BLOCK_SIZE+1
+ # Add some more bytes to each input until we hit MAX_BLOCK_BASE_SIZE+1
extra_bytes = min(additional_bytes+1, 55)
block.vtx[-1].wit.vtxinwit[int(i/(2*NUM_DROPS))].scriptWitness.stack[i%(2*NUM_DROPS)] = b'a'*(195+extra_bytes)
additional_bytes -= extra_bytes
@@ -556,7 +493,7 @@ class SegWitTest(BitcoinTestFramework):
add_witness_commitment(block)
block.solve()
vsize = get_virtual_size(block)
- assert_equal(vsize, MAX_BLOCK_SIZE + 1)
+ assert_equal(vsize, MAX_BLOCK_BASE_SIZE + 1)
# Make sure that our test case would exceed the old max-network-message
# limit
assert(len(block.serialize(True)) > 2*1024*1024)
@@ -569,7 +506,7 @@ class SegWitTest(BitcoinTestFramework):
block.vtx[0].vout.pop()
add_witness_commitment(block)
block.solve()
- assert(get_virtual_size(block) == MAX_BLOCK_SIZE)
+ assert(get_virtual_size(block) == MAX_BLOCK_BASE_SIZE)
self.test_node.test_witness_block(block, accepted=True)
@@ -617,7 +554,7 @@ class SegWitTest(BitcoinTestFramework):
# Consensus tests of extra witness data in a transaction.
def test_extra_witness_data(self):
- print("\tTesting extra witness data in tx")
+ self.log.info("Testing extra witness data in tx")
assert(len(self.utxo) > 0)
@@ -693,7 +630,7 @@ class SegWitTest(BitcoinTestFramework):
def test_max_witness_push_length(self):
''' Should only allow up to 520 byte pushes in witness stack '''
- print("\tTesting maximum witness push size")
+ self.log.info("Testing maximum witness push size")
MAX_SCRIPT_ELEMENT_SIZE = 520
assert(len(self.utxo))
@@ -733,7 +670,7 @@ class SegWitTest(BitcoinTestFramework):
def test_max_witness_program_length(self):
# Can create witness outputs that are long, but can't be greater than
# 10k bytes to successfully spend
- print("\tTesting maximum witness program length")
+ self.log.info("Testing maximum witness program length")
assert(len(self.utxo))
MAX_PROGRAM_LENGTH = 10000
@@ -782,7 +719,7 @@ class SegWitTest(BitcoinTestFramework):
def test_witness_input_length(self):
''' Ensure that vin length must match vtxinwit length '''
- print("\tTesting witness input length")
+ self.log.info("Testing witness input length")
assert(len(self.utxo))
witness_program = CScript([OP_DROP, OP_TRUE])
@@ -865,7 +802,7 @@ class SegWitTest(BitcoinTestFramework):
def test_witness_tx_relay_before_segwit_activation(self):
- print("\tTesting relay of witness transactions")
+ self.log.info("Testing relay of witness transactions")
# Generate a transaction that doesn't require a witness, but send it
# with a witness. Should be rejected for premature-witness, but should
# not be added to recently rejected list.
@@ -883,13 +820,13 @@ class SegWitTest(BitcoinTestFramework):
# Verify that if a peer doesn't set nServices to include NODE_WITNESS,
# the getdata is just for the non-witness portion.
self.old_node.announce_tx_and_wait_for_getdata(tx)
- assert(self.old_node.last_getdata.inv[0].type == 1)
+ assert(self.old_node.last_message["getdata"].inv[0].type == 1)
# Since we haven't delivered the tx yet, inv'ing the same tx from
# a witness transaction ought not result in a getdata.
try:
self.test_node.announce_tx_and_wait_for_getdata(tx, timeout=2)
- print("Error: duplicate tx getdata!")
+ self.log.error("Error: duplicate tx getdata!")
assert(False)
except AssertionError as e:
pass
@@ -904,14 +841,6 @@ class SegWitTest(BitcoinTestFramework):
# But eliminating the witness should fix it
self.test_node.test_transaction_acceptance(tx, with_witness=False, accepted=True)
- # Verify that inv's to test_node come with getdata's for non-witness tx's
- # Just tweak the transaction, announce it, and verify we get a getdata
- # for a normal tx
- tx.vout[0].scriptPubKey = CScript([OP_TRUE, OP_TRUE])
- tx.rehash()
- self.test_node.announce_tx_and_wait_for_getdata(tx)
- assert(self.test_node.last_getdata.inv[0].type == 1)
-
# Cleanup: mine the first transaction and update utxo
self.nodes[0].generate(1)
assert_equal(len(self.nodes[0].getrawmempool()), 0)
@@ -925,7 +854,7 @@ class SegWitTest(BitcoinTestFramework):
# - accepts transactions with valid witnesses
# and that witness transactions are relayed to non-upgraded peers.
def test_tx_relay_after_segwit_activation(self):
- print("\tTesting relay of witness transactions")
+ self.log.info("Testing relay of witness transactions")
# Generate a transaction that doesn't require a witness, but send it
# with a witness. Should be rejected because we can't use a witness
# when spending a non-witness output.
@@ -938,7 +867,6 @@ class SegWitTest(BitcoinTestFramework):
tx.rehash()
tx_hash = tx.sha256
- tx_value = tx.vout[0].nValue
# Verify that unnecessary witnesses are rejected.
self.test_node.announce_tx_and_wait_for_getdata(tx)
@@ -946,8 +874,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_node.test_transaction_acceptance(tx, with_witness=True, accepted=False)
# Verify that removing the witness succeeds.
- # Re-announcing won't result in a getdata for ~2.5 minutes, so just
- # deliver the modified transaction.
+ self.test_node.announce_tx_and_wait_for_getdata(tx)
self.test_node.test_transaction_acceptance(tx, with_witness=False, accepted=True)
# Now try to add extra witness data to a valid witness tx.
@@ -961,8 +888,24 @@ class SegWitTest(BitcoinTestFramework):
tx3 = CTransaction()
tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
- tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, CScript([OP_TRUE])))
tx3.wit.vtxinwit.append(CTxInWitness())
+
+ # Add too-large for IsStandard witness and check that it does not enter reject filter
+ p2sh_program = CScript([OP_TRUE])
+ p2sh_pubkey = hash160(p2sh_program)
+ witness_program2 = CScript([b'a'*400000])
+ tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])))
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program2]
+ tx3.rehash()
+
+ # Node will not be blinded to the transaction
+ self.std_node.announce_tx_and_wait_for_getdata(tx3)
+ self.std_node.test_transaction_acceptance(tx3, True, False, b'tx-size')
+ self.std_node.announce_tx_and_wait_for_getdata(tx3)
+ self.std_node.test_transaction_acceptance(tx3, True, False, b'tx-size')
+
+ # Remove witness stuffing, instead add extra witness push on stack
+ tx3.vout[0] = CTxOut(tx2.vout[0].nValue-1000, CScript([OP_TRUE]))
tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), witness_program ]
tx3.rehash()
@@ -973,9 +916,9 @@ class SegWitTest(BitcoinTestFramework):
tx3.wit.vtxinwit[0].scriptWitness.stack = [ witness_program ]
# Also check that old_node gets a tx announcement, even though this is
# a witness transaction.
- self.old_node.wait_for_inv(CInv(1, tx2.sha256)) # wait until tx2 was inv'ed
+ self.old_node.wait_for_inv([CInv(1, tx2.sha256)]) # wait until tx2 was inv'ed
self.test_node.test_transaction_acceptance(tx3, with_witness=True, accepted=True)
- self.old_node.wait_for_inv(CInv(1, tx3.sha256))
+ self.old_node.wait_for_inv([CInv(1, tx3.sha256)])
# Test that getrawtransaction returns correct witness information
# hash, size, vsize
@@ -1000,9 +943,9 @@ class SegWitTest(BitcoinTestFramework):
# This is true regardless of segwit activation.
# Also test that we don't ask for blocks from unupgraded peers
def test_block_relay(self, segwit_activated):
- print("\tTesting block relay")
+ self.log.info("Testing block relay")
- blocktype = 2|MSG_WITNESS_FLAG if segwit_activated else 2
+ blocktype = 2|MSG_WITNESS_FLAG
# test_node has set NODE_WITNESS, so all getdata requests should be for
# witness blocks.
@@ -1012,20 +955,20 @@ class SegWitTest(BitcoinTestFramework):
block1.solve()
self.test_node.announce_block_and_wait_for_getdata(block1, use_header=False)
- assert(self.test_node.last_getdata.inv[0].type == blocktype)
+ assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
self.test_node.test_witness_block(block1, True)
block2 = self.build_next_block(nVersion=4)
block2.solve()
self.test_node.announce_block_and_wait_for_getdata(block2, use_header=True)
- assert(self.test_node.last_getdata.inv[0].type == blocktype)
+ assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
self.test_node.test_witness_block(block2, True)
block3 = self.build_next_block(nVersion=(VB_TOP_BITS | (1<<15)))
block3.solve()
self.test_node.announce_block_and_wait_for_getdata(block3, use_header=True)
- assert(self.test_node.last_getdata.inv[0].type == blocktype)
+ assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
self.test_node.test_witness_block(block3, True)
# Check that we can getdata for witness blocks or regular blocks,
@@ -1065,31 +1008,112 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(wit_block.serialize(False), non_wit_block.serialize())
assert_equal(wit_block.serialize(True), block.serialize(True))
- # Test size, vsize, cost
+ # Test size, vsize, weight
rpc_details = self.nodes[0].getblock(block.hash, True)
assert_equal(rpc_details["size"], len(block.serialize(True)))
assert_equal(rpc_details["strippedsize"], len(block.serialize(False)))
- cost = 3*len(block.serialize(False)) + len(block.serialize(True))
- assert_equal(rpc_details["cost"], cost)
+ weight = 3*len(block.serialize(False)) + len(block.serialize(True))
+ assert_equal(rpc_details["weight"], weight)
# Upgraded node should not ask for blocks from unupgraded
block4 = self.build_next_block(nVersion=4)
block4.solve()
self.old_node.getdataset = set()
+
# Blocks can be requested via direct-fetch (immediately upon processing the announcement)
# or via parallel download (with an indeterminate delay from processing the announcement)
# so to test that a block is NOT requested, we could guess a time period to sleep for,
# and then check. We can avoid the sleep() by taking advantage of transaction getdata's
# being processed after block getdata's, and announce a transaction as well,
# and then check to see if that particular getdata has been received.
- self.old_node.announce_block(block4, use_header=False)
+ # Since 0.14, inv's will only be responded to with a getheaders, so send a header
+ # to announce this block.
+ msg = msg_headers()
+ msg.headers = [ CBlockHeader(block4) ]
+ self.old_node.send_message(msg)
self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0])
assert(block4.sha256 not in self.old_node.getdataset)
+ # V0 segwit outputs should be standard after activation, but not before.
+ def test_standardness_v0(self, segwit_activated):
+ self.log.info("Testing standardness of v0 outputs (%s activation)" % ("after" if segwit_activated else "before"))
+ assert(len(self.utxo))
+
+ witness_program = CScript([OP_TRUE])
+ witness_hash = sha256(witness_program)
+ scriptPubKey = CScript([OP_0, witness_hash])
+
+ p2sh_pubkey = hash160(witness_program)
+ p2sh_scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
+
+ # First prepare a p2sh output (so that spending it will pass standardness)
+ p2sh_tx = CTransaction()
+ p2sh_tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b"")]
+ p2sh_tx.vout = [CTxOut(self.utxo[0].nValue-1000, p2sh_scriptPubKey)]
+ p2sh_tx.rehash()
+
+ # Mine it on test_node to create the confirmed output.
+ self.test_node.test_transaction_acceptance(p2sh_tx, with_witness=True, accepted=True)
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+
+ # Now test standardness of v0 P2WSH outputs.
+ # Start by creating a transaction with two outputs.
+ tx = CTransaction()
+ tx.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
+ tx.vout = [CTxOut(p2sh_tx.vout[0].nValue-10000, scriptPubKey)]
+ tx.vout.append(CTxOut(8000, scriptPubKey)) # Might burn this later
+ tx.rehash()
+
+ self.std_node.test_transaction_acceptance(tx, with_witness=True, accepted=segwit_activated)
+
+ # Now create something that looks like a P2PKH output. This won't be spendable.
+ scriptPubKey = CScript([OP_0, hash160(witness_hash)])
+ tx2 = CTransaction()
+ if segwit_activated:
+ # if tx was accepted, then we spend the second output.
+ tx2.vin = [CTxIn(COutPoint(tx.sha256, 1), b"")]
+ tx2.vout = [CTxOut(7000, scriptPubKey)]
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
+ else:
+ # if tx wasn't accepted, we just re-spend the p2sh output we started with.
+ tx2.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
+ tx2.vout = [CTxOut(p2sh_tx.vout[0].nValue-1000, scriptPubKey)]
+ tx2.rehash()
+
+ self.std_node.test_transaction_acceptance(tx2, with_witness=True, accepted=segwit_activated)
+
+ # Now update self.utxo for later tests.
+ tx3 = CTransaction()
+ if segwit_activated:
+ # tx and tx2 were both accepted. Don't bother trying to reclaim the
+ # P2PKH output; just send tx's first output back to an anyone-can-spend.
+ sync_mempools([self.nodes[0], self.nodes[1]])
+ tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
+ tx3.vout = [CTxOut(tx.vout[0].nValue-1000, CScript([OP_TRUE]))]
+ tx3.wit.vtxinwit.append(CTxInWitness())
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
+ tx3.rehash()
+ self.test_node.test_transaction_acceptance(tx3, with_witness=True, accepted=True)
+ else:
+ # tx and tx2 didn't go anywhere; just clean up the p2sh_tx output.
+ tx3.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]
+ tx3.vout = [CTxOut(p2sh_tx.vout[0].nValue-1000, witness_program)]
+ tx3.rehash()
+ self.test_node.test_transaction_acceptance(tx3, with_witness=True, accepted=True)
+
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
+ assert_equal(len(self.nodes[1].getrawmempool()), 0)
+
+
# Verify that future segwit upgraded transactions are non-standard,
# but valid in blocks. Can run this before and after segwit activation.
def test_segwit_versions(self):
- print("\tTesting standardness/consensus for segwit versions (0-16)")
+ self.log.info("Testing standardness/consensus for segwit versions (0-16)")
assert(len(self.utxo))
NUM_TESTS = 17 # will test OP_0, OP1, ..., OP_16
if (len(self.utxo) < NUM_TESTS):
@@ -1160,7 +1184,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_node.test_transaction_acceptance(tx3, with_witness=True, accepted=False)
self.test_node.sync_with_ping()
with mininode_lock:
- assert(b"reserved for soft-fork upgrades" in self.test_node.last_reject.reason)
+ assert(b"reserved for soft-fork upgrades" in self.test_node.last_message["reject"].reason)
# Building a block with the transaction must be valid, however.
block = self.build_next_block()
@@ -1173,7 +1197,7 @@ class SegWitTest(BitcoinTestFramework):
def test_premature_coinbase_witness_spend(self):
- print("\tTesting premature coinbase witness spend")
+ self.log.info("Testing premature coinbase witness spend")
block = self.build_next_block()
# Change the output of the block to be a witness output.
witness_program = CScript([OP_TRUE])
@@ -1208,7 +1232,7 @@ class SegWitTest(BitcoinTestFramework):
def test_signature_version_1(self):
- print("\tTesting segwit signature hash version 1")
+ self.log.info("Testing segwit signature hash version 1")
key = CECKey()
key.set_secretbytes(b"9")
pubkey = CPubKey(key.get_pubkey())
@@ -1232,13 +1256,6 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
self.utxo.pop(0)
- # Add signature for a P2PK witness program.
- def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key):
- tx_hash = SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, value)
- signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
- txTo.wit.vtxinwit[inIdx].scriptWitness.stack = [signature, script]
- txTo.rehash()
-
# Test each hashtype
prev_utxo = UTXO(tx.sha256, 0, tx.vout[0].nValue)
for sigflag in [ 0, SIGHASH_ANYONECANPAY ]:
@@ -1293,6 +1310,9 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
used_sighash_single_out_of_bounds = False
for i in range(NUM_TESTS):
+ # Ping regularly to keep the connection alive
+ if (not i % 100):
+ self.test_node.sync_with_ping()
# Choose random number of inputs to use.
num_inputs = random.randint(1, 10)
# Create a slight bias for producing more utxos
@@ -1325,13 +1345,13 @@ class SegWitTest(BitcoinTestFramework):
block.vtx.append(tx)
# Test the block periodically, if we're close to maxblocksize
- if (get_virtual_size(block) > MAX_BLOCK_SIZE - 1000):
+ if (get_virtual_size(block) > MAX_BLOCK_BASE_SIZE - 1000):
self.update_witness_block_with_transactions(block, [])
self.test_node.test_witness_block(block, accepted=True)
block = self.build_next_block()
if (not used_sighash_single_out_of_bounds):
- print("WARNING: this test run didn't attempt SIGHASH_SINGLE with out-of-bounds index value")
+ self.log.info("WARNING: this test run didn't attempt SIGHASH_SINGLE with out-of-bounds index value")
# Test the transactions we've added to the block
if (len(block.vtx) > 1):
self.update_witness_block_with_transactions(block, [])
@@ -1349,7 +1369,7 @@ class SegWitTest(BitcoinTestFramework):
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE])))
- script = CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])
+ script = GetP2PKHScript(pubkeyhash)
sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
@@ -1394,7 +1414,7 @@ class SegWitTest(BitcoinTestFramework):
# Test P2SH wrapped witness programs.
def test_p2sh_witness(self, segwit_activated):
- print("\tTesting P2SH witness transactions")
+ self.log.info("Testing P2SH witness transactions")
assert(len(self.utxo))
@@ -1467,7 +1487,7 @@ class SegWitTest(BitcoinTestFramework):
# To enable this test, pass --oldbinary=<path-to-pre-segwit-bitcoind> to
# the test.
def test_upgrade_after_activation(self, node, node_id):
- print("\tTesting software upgrade after softfork activation")
+ self.log.info("Testing software upgrade after softfork activation")
assert(node_id != 0) # node0 is assumed to be a segwit-active bitcoind
@@ -1476,7 +1496,7 @@ class SegWitTest(BitcoinTestFramework):
# Restart with the new binary
stop_node(node, node_id)
- self.nodes[node_id] = start_node(node_id, self.options.tmpdir, ["-debug"])
+ self.nodes[node_id] = start_node(node_id, self.options.tmpdir)
connect_nodes(self.nodes[0], node_id)
sync_blocks(self.nodes)
@@ -1495,7 +1515,7 @@ class SegWitTest(BitcoinTestFramework):
def test_witness_sigops(self):
'''Ensure sigop counting is correct inside witnesses.'''
- print("\tTesting sigops limit")
+ self.log.info("Testing sigops limit")
assert(len(self.utxo))
@@ -1562,7 +1582,7 @@ class SegWitTest(BitcoinTestFramework):
# too many sigops (contributing to legacy sigop count).
checksig_count = (extra_sigops_available // 4) + 1
scriptPubKey_checksigs = CScript([OP_CHECKSIG]*checksig_count)
- tx2.vout.append(CTxOut(0, scriptPubKey_checksigs));
+ tx2.vout.append(CTxOut(0, scriptPubKey_checksigs))
tx2.vin.pop()
tx2.wit.vtxinwit.pop()
tx2.vout[0].nValue -= tx.vout[-2].nValue
@@ -1597,20 +1617,256 @@ class SegWitTest(BitcoinTestFramework):
# TODO: test p2sh sigop counting
def test_getblocktemplate_before_lockin(self):
- print("\tTesting getblocktemplate setting of segwit versionbit (before lockin)")
- block_version = (self.nodes[0].getblocktemplate())['version']
- assert_equal(block_version & (1 << VB_WITNESS_BIT), 0)
+ self.log.info("Testing getblocktemplate setting of segwit versionbit (before lockin)")
+ # Node0 is segwit aware, node2 is not.
+ for node in [self.nodes[0], self.nodes[2]]:
+ gbt_results = node.getblocktemplate()
+ block_version = gbt_results['version']
+ # If we're not indicating segwit support, we will still be
+ # signalling for segwit activation.
+ assert_equal((block_version & (1 << VB_WITNESS_BIT) != 0), node == self.nodes[0])
+ # If we don't specify the segwit rule, then we won't get a default
+ # commitment.
+ assert('default_witness_commitment' not in gbt_results)
# Workaround:
# Can either change the tip, or change the mempool and wait 5 seconds
# to trigger a recomputation of getblocktemplate.
- self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+ txid = int(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1), 16)
# Using mocktime lets us avoid sleep()
+ sync_mempools(self.nodes)
self.nodes[0].setmocktime(int(time.time())+10)
+ self.nodes[2].setmocktime(int(time.time())+10)
+
+ for node in [self.nodes[0], self.nodes[2]]:
+ gbt_results = node.getblocktemplate({"rules" : ["segwit"]})
+ block_version = gbt_results['version']
+ if node == self.nodes[2]:
+ # If this is a non-segwit node, we should still not get a witness
+ # commitment, nor a version bit signalling segwit.
+ assert_equal(block_version & (1 << VB_WITNESS_BIT), 0)
+ assert('default_witness_commitment' not in gbt_results)
+ else:
+ # For segwit-aware nodes, check the version bit and the witness
+ # commitment are correct.
+ assert(block_version & (1 << VB_WITNESS_BIT) != 0)
+ assert('default_witness_commitment' in gbt_results)
+ witness_commitment = gbt_results['default_witness_commitment']
+
+ # Check that default_witness_commitment is present.
+ witness_root = CBlock.get_merkle_root([ser_uint256(0),
+ ser_uint256(txid)])
+ script = get_witness_script(witness_root, 0)
+ assert_equal(witness_commitment, bytes_to_hex_str(script))
+
+ # undo mocktime
+ self.nodes[0].setmocktime(0)
+ self.nodes[2].setmocktime(0)
+
+ # Uncompressed pubkeys are no longer supported in default relay policy,
+ # but (for now) are still valid in blocks.
+ def test_uncompressed_pubkey(self):
+ self.log.info("Testing uncompressed pubkeys")
+ # Segwit transactions using uncompressed pubkeys are not accepted
+ # under default policy, but should still pass consensus.
+ key = CECKey()
+ key.set_secretbytes(b"9")
+ key.set_compressed(False)
+ pubkey = CPubKey(key.get_pubkey())
+ assert_equal(len(pubkey), 65) # This should be an uncompressed pubkey
+
+ assert(len(self.utxo) > 0)
+ utxo = self.utxo.pop(0)
+
+ # Test 1: P2WPKH
+ # First create a P2WPKH output that uses an uncompressed pubkey
+ pubkeyhash = hash160(pubkey)
+ scriptPKH = CScript([OP_0, pubkeyhash])
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(utxo.sha256, utxo.n), b""))
+ tx.vout.append(CTxOut(utxo.nValue-1000, scriptPKH))
+ tx.rehash()
+
+ # Confirm it in a block.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx])
+ self.test_node.test_witness_block(block, accepted=True)
+
+ # Now try to spend it. Send it to a P2WSH output, which we'll
+ # use in the next test.
+ witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])
+ witness_hash = sha256(witness_program)
+ scriptWSH = CScript([OP_0, witness_hash])
+
+ tx2 = CTransaction()
+ tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
+ tx2.vout.append(CTxOut(tx.vout[0].nValue-1000, scriptWSH))
+ script = GetP2PKHScript(pubkeyhash)
+ sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
+ signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ tx2.wit.vtxinwit.append(CTxInWitness())
+ tx2.wit.vtxinwit[0].scriptWitness.stack = [ signature, pubkey ]
+ tx2.rehash()
+
+ # Should fail policy test.
+ self.test_node.test_transaction_acceptance(tx2, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ # But passes consensus.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx2])
+ self.test_node.test_witness_block(block, accepted=True)
+
+ # Test 2: P2WSH
+ # Try to spend the P2WSH output created in last test.
+ # Send it to a P2SH(P2WSH) output, which we'll use in the next test.
+ p2sh_witness_hash = hash160(scriptWSH)
+ scriptP2SH = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])
+ scriptSig = CScript([scriptWSH])
+
+ tx3 = CTransaction()
+ tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
+ tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, scriptP2SH))
+ tx3.wit.vtxinwit.append(CTxInWitness())
+ sign_P2PK_witness_input(witness_program, tx3, 0, SIGHASH_ALL, tx2.vout[0].nValue, key)
+
+ # Should fail policy test.
+ self.test_node.test_transaction_acceptance(tx3, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ # But passes consensus.
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx3])
+ self.test_node.test_witness_block(block, accepted=True)
+
+ # Test 3: P2SH(P2WSH)
+ # Try to spend the P2SH output created in the last test.
+ # Send it to a P2PKH output, which we'll use in the next test.
+ scriptPubKey = GetP2PKHScript(pubkeyhash)
+ tx4 = CTransaction()
+ tx4.vin.append(CTxIn(COutPoint(tx3.sha256, 0), scriptSig))
+ tx4.vout.append(CTxOut(tx3.vout[0].nValue-1000, scriptPubKey))
+ tx4.wit.vtxinwit.append(CTxInWitness())
+ sign_P2PK_witness_input(witness_program, tx4, 0, SIGHASH_ALL, tx3.vout[0].nValue, key)
+
+ # Should fail policy test.
+ self.test_node.test_transaction_acceptance(tx4, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx4])
+ self.test_node.test_witness_block(block, accepted=True)
+
+ # Test 4: Uncompressed pubkeys should still be valid in non-segwit
+ # transactions.
+ tx5 = CTransaction()
+ tx5.vin.append(CTxIn(COutPoint(tx4.sha256, 0), b""))
+ tx5.vout.append(CTxOut(tx4.vout[0].nValue-1000, CScript([OP_TRUE])))
+ (sig_hash, err) = SignatureHash(scriptPubKey, tx5, 0, SIGHASH_ALL)
+ signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ tx5.vin[0].scriptSig = CScript([signature, pubkey])
+ tx5.rehash()
+ # Should pass policy and consensus.
+ self.test_node.test_transaction_acceptance(tx5, True, True)
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx5])
+ self.test_node.test_witness_block(block, accepted=True)
+ self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))
+
+ def test_non_standard_witness(self):
+ self.log.info("Testing detection of non-standard P2WSH witness")
+ pad = chr(1).encode('latin-1')
+
+ # Create scripts for tests
+ scripts = []
+ scripts.append(CScript([OP_DROP] * 100))
+ scripts.append(CScript([OP_DROP] * 99))
+ scripts.append(CScript([pad * 59] * 59 + [OP_DROP] * 60))
+ scripts.append(CScript([pad * 59] * 59 + [OP_DROP] * 61))
+
+ p2wsh_scripts = []
+
+ assert(len(self.utxo))
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
+
+ # For each script, generate a pair of P2WSH and P2SH-P2WSH output.
+ outputvalue = (self.utxo[0].nValue - 1000) // (len(scripts) * 2)
+ for i in scripts:
+ p2wsh = CScript([OP_0, sha256(i)])
+ p2sh = hash160(p2wsh)
+ p2wsh_scripts.append(p2wsh)
+ tx.vout.append(CTxOut(outputvalue, p2wsh))
+ tx.vout.append(CTxOut(outputvalue, CScript([OP_HASH160, p2sh, OP_EQUAL])))
+ tx.rehash()
+ txid = tx.sha256
+ self.test_node.test_transaction_acceptance(tx, with_witness=False, accepted=True)
+
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+
+ # Creating transactions for tests
+ p2wsh_txs = []
+ p2sh_txs = []
+ for i in range(len(scripts)):
+ p2wsh_tx = CTransaction()
+ p2wsh_tx.vin.append(CTxIn(COutPoint(txid,i*2)))
+ p2wsh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(""))])))
+ p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
+ p2wsh_tx.rehash()
+ p2wsh_txs.append(p2wsh_tx)
+ p2sh_tx = CTransaction()
+ p2sh_tx.vin.append(CTxIn(COutPoint(txid,i*2+1), CScript([p2wsh_scripts[i]])))
+ p2sh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(""))])))
+ p2sh_tx.wit.vtxinwit.append(CTxInWitness())
+ p2sh_tx.rehash()
+ p2sh_txs.append(p2sh_tx)
+
+ # Testing native P2WSH
+ # Witness stack size, excluding witnessScript, over 100 is non-standard
+ p2wsh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]
+ self.std_node.test_transaction_acceptance(p2wsh_txs[0], True, False, b'bad-witness-nonstandard')
+ # Non-standard nodes should accept
+ self.test_node.test_transaction_acceptance(p2wsh_txs[0], True, True)
+
+ # Stack element size over 80 bytes is non-standard
+ p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]
+ self.std_node.test_transaction_acceptance(p2wsh_txs[1], True, False, b'bad-witness-nonstandard')
+ # Non-standard nodes should accept
+ self.test_node.test_transaction_acceptance(p2wsh_txs[1], True, True)
+ # Standard nodes should accept if element size is not over 80 bytes
+ p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]
+ self.std_node.test_transaction_acceptance(p2wsh_txs[1], True, True)
+
+ # witnessScript size at 3600 bytes is standard
+ p2wsh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]
+ self.test_node.test_transaction_acceptance(p2wsh_txs[2], True, True)
+ self.std_node.test_transaction_acceptance(p2wsh_txs[2], True, True)
+
+ # witnessScript size at 3601 bytes is non-standard
+ p2wsh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]
+ self.std_node.test_transaction_acceptance(p2wsh_txs[3], True, False, b'bad-witness-nonstandard')
+ # Non-standard nodes should accept
+ self.test_node.test_transaction_acceptance(p2wsh_txs[3], True, True)
+
+ # Repeating the same tests with P2SH-P2WSH
+ p2sh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]
+ self.std_node.test_transaction_acceptance(p2sh_txs[0], True, False, b'bad-witness-nonstandard')
+ self.test_node.test_transaction_acceptance(p2sh_txs[0], True, True)
+ p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]
+ self.std_node.test_transaction_acceptance(p2sh_txs[1], True, False, b'bad-witness-nonstandard')
+ self.test_node.test_transaction_acceptance(p2sh_txs[1], True, True)
+ p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]
+ self.std_node.test_transaction_acceptance(p2sh_txs[1], True, True)
+ p2sh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]
+ self.test_node.test_transaction_acceptance(p2sh_txs[2], True, True)
+ self.std_node.test_transaction_acceptance(p2sh_txs[2], True, True)
+ p2sh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]
+ self.std_node.test_transaction_acceptance(p2sh_txs[3], True, False, b'bad-witness-nonstandard')
+ self.test_node.test_transaction_acceptance(p2sh_txs[3], True, True)
+
+ self.nodes[0].generate(1) # Mine and clean up the mempool of non-standard node
+ # Valid but non-standard transactions in a block should be accepted by standard node
+ sync_blocks(self.nodes)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
+ assert_equal(len(self.nodes[1].getrawmempool()), 0)
+
+ self.utxo.pop(0)
- block_version = self.nodes[0].getblocktemplate({"rules" : ["segwit"]})['version']
- assert(block_version & (1 << VB_WITNESS_BIT) != 0)
- self.nodes[0].setmocktime(0) # undo mocktime
def run_test(self):
# Setup the p2p connections and start up the network thread.
@@ -1636,7 +1892,7 @@ class SegWitTest(BitcoinTestFramework):
# Test logic begins here
self.test_node.wait_for_verack()
- print("\nStarting tests before segwit lock in:")
+ self.log.info("Starting tests before segwit lock in:")
self.test_witness_services() # Verifies NODE_WITNESS
self.test_non_witness_transaction() # non-witness tx's are accepted
@@ -1645,12 +1901,13 @@ class SegWitTest(BitcoinTestFramework):
# Advance to segwit being 'started'
self.advance_to_segwit_started()
+ sync_blocks(self.nodes)
self.test_getblocktemplate_before_lockin()
sync_blocks(self.nodes)
# At lockin, nothing should change.
- print("\nTesting behavior post lockin, pre-activation")
+ self.log.info("Testing behavior post lockin, pre-activation")
self.advance_to_segwit_lockin()
# Retest unnecessary witnesses
@@ -1658,11 +1915,12 @@ class SegWitTest(BitcoinTestFramework):
self.test_witness_tx_relay_before_segwit_activation()
self.test_block_relay(segwit_activated=False)
self.test_p2sh_witness(segwit_activated=False)
+ self.test_standardness_v0(segwit_activated=False)
sync_blocks(self.nodes)
# Now activate segwit
- print("\nTesting behavior after segwit activation")
+ self.log.info("Testing behavior after segwit activation")
self.advance_to_segwit_active()
sync_blocks(self.nodes)
@@ -1679,14 +1937,14 @@ class SegWitTest(BitcoinTestFramework):
self.test_witness_input_length()
self.test_block_relay(segwit_activated=True)
self.test_tx_relay_after_segwit_activation()
+ self.test_standardness_v0(segwit_activated=True)
self.test_segwit_versions()
self.test_premature_coinbase_witness_spend()
+ self.test_uncompressed_pubkey()
self.test_signature_version_1()
+ self.test_non_standard_witness()
sync_blocks(self.nodes)
- if self.test_upgrade:
- self.test_upgrade_after_activation(self.nodes[2], 2)
- else:
- print("\tSkipping upgrade-after-activation test (use --oldbinary to enable)")
+ self.test_upgrade_after_activation(self.nodes[2], 2)
self.test_witness_sigops()
diff --git a/test/functional/p2p-timeouts.py b/test/functional/p2p-timeouts.py
new file mode 100755
index 0000000000..c3b29c215b
--- /dev/null
+++ b/test/functional/p2p-timeouts.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Test various net timeouts.
+
+- Create three bitcoind nodes:
+
+ no_verack_node - we never send a verack in response to their version
+ no_version_node - we never send a version (only a ping)
+ no_send_node - we never send any P2P message.
+
+- Start all three nodes
+- Wait 1 second
+- Assert that we're connected
+- Send a ping to no_verack_node and no_version_node
+- Wait 30 seconds
+- Assert that we're still connected
+- Send a ping to no_verack_node and no_version_node
+- Wait 31 seconds
+- Assert that we're no longer connected (timeout to receive version/verack is 60 seconds)
+"""
+
+from time import sleep
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+class TestNode(NodeConnCB):
+ def on_version(self, conn, message):
+ # Don't send a verack in response
+ pass
+
+class TimeoutsTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def run_test(self):
+ # Setup the p2p connections and start up the network thread.
+ self.no_verack_node = TestNode() # never send verack
+ self.no_version_node = TestNode() # never send version (just ping)
+ self.no_send_node = TestNode() # never send anything
+
+ connections = []
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_verack_node))
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_version_node, send_version=False))
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_send_node, send_version=False))
+ self.no_verack_node.add_connection(connections[0])
+ self.no_version_node.add_connection(connections[1])
+ self.no_send_node.add_connection(connections[2])
+
+ NetworkThread().start() # Start up network handling in another thread
+
+ sleep(1)
+
+ assert(self.no_verack_node.connected)
+ assert(self.no_version_node.connected)
+ assert(self.no_send_node.connected)
+
+ ping_msg = msg_ping()
+ connections[0].send_message(ping_msg)
+ connections[1].send_message(ping_msg)
+
+ sleep(30)
+
+ assert "version" in self.no_verack_node.last_message
+
+ assert(self.no_verack_node.connected)
+ assert(self.no_version_node.connected)
+ assert(self.no_send_node.connected)
+
+ connections[0].send_message(ping_msg)
+ connections[1].send_message(ping_msg)
+
+ sleep(31)
+
+ assert(not self.no_verack_node.connected)
+ assert(not self.no_version_node.connected)
+ assert(not self.no_send_node.connected)
+
+if __name__ == '__main__':
+ TimeoutsTest().main()
diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py
index 962cafef0b..41921fe14e 100755
--- a/qa/rpc-tests/p2p-versionbits-warning.py
+++ b/test/functional/p2p-versionbits-warning.py
@@ -2,62 +2,31 @@
# Copyright (c) 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.
+"""Test version bits warning system.
+
+Generate chains with block versions that appear to be signalling unknown
+soft-forks, and test that warning alerts are generated.
+"""
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-import time
+import re
from test_framework.blocktools import create_block, create_coinbase
-'''
-Test version bits' warning system.
-
-Generate chains with block versions that appear to be signalling unknown
-soft-forks, and test that warning alerts are generated.
-'''
-
VB_PERIOD = 144 # versionbits period length for regtest
VB_THRESHOLD = 108 # versionbits activation threshold for regtest
VB_TOP_BITS = 0x20000000
VB_UNKNOWN_BIT = 27 # Choose a bit unassigned to any deployment
-# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending
-# p2p messages to a node, generating the messages in the main testing logic.
-class TestNode(NodeConnCB):
- def __init__(self):
- NodeConnCB.__init__(self)
- self.connection = None
- self.ping_counter = 1
- self.last_pong = msg_pong()
-
- def add_connection(self, conn):
- self.connection = conn
+WARN_UNKNOWN_RULES_MINED = "Unknown block versions being mined! It's possible unknown rules are in effect"
+WARN_UNKNOWN_RULES_ACTIVE = "unknown new rules activated (versionbit {})".format(VB_UNKNOWN_BIT)
+VB_PATTERN = re.compile("^Warning.*versionbit")
+class TestNode(NodeConnCB):
def on_inv(self, conn, message):
pass
- # Wrapper for the NodeConn's send_message function
- def send_message(self, message):
- self.connection.send_message(message)
-
- def on_pong(self, conn, message):
- self.last_pong = message
-
- # Sync up with the node after delivery of a block
- def sync_with_ping(self, timeout=30):
- self.connection.send_message(msg_ping(nonce=self.ping_counter))
- received_pong = False
- sleep_time = 0.05
- while not received_pong and timeout > 0:
- time.sleep(sleep_time)
- timeout -= sleep_time
- with mininode_lock:
- if self.last_pong.nonce == self.ping_counter:
- received_pong = True
- self.ping_counter += 1
- return received_pong
-
-
class VersionBitsWarningTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
@@ -65,16 +34,12 @@ class VersionBitsWarningTest(BitcoinTestFramework):
self.num_nodes = 1
def setup_network(self):
- self.nodes = []
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
# Open and close to create zero-length file
- with open(self.alert_filename, 'w') as f:
+ with open(self.alert_filename, 'w', encoding='utf8') as _:
pass
- self.node_options = ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]
- self.nodes.append(start_node(0, self.options.tmpdir, self.node_options))
-
- import re
- self.vb_pattern = re.compile("^Warning.*versionbit")
+ self.extra_args = [["-alertnotify=echo %s >> \"" + self.alert_filename + "\""]]
+ self.setup_nodes()
# Send numblocks blocks via peer with nVersionToUse set.
def send_blocks_with_version(self, peer, numblocks, nVersionToUse):
@@ -83,7 +48,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
block_time = self.nodes[0].getblockheader(tip)["time"]+1
tip = int(tip, 16)
- for i in range(numblocks):
+ for _ in range(numblocks):
block = create_block(tip, create_coinbase(height+1), block_time)
block.nVersion = nVersionToUse
block.solve()
@@ -94,9 +59,9 @@ class VersionBitsWarningTest(BitcoinTestFramework):
peer.sync_with_ping()
def test_versionbits_in_alert_file(self):
- with open(self.alert_filename, 'r') as f:
+ with open(self.alert_filename, 'r', encoding='utf8') as f:
alert_text = f.read()
- assert(self.vb_pattern.match(alert_text))
+ assert(VB_PATTERN.match(alert_text))
def run_test(self):
# Setup the p2p connection and start up the network thread.
@@ -122,8 +87,10 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# Fill rest of period with regular version blocks
self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD + 1)
# Check that we're not getting any versionbit-related errors in
- # getinfo()
- assert(not self.vb_pattern.match(self.nodes[0].getinfo()["errors"]))
+ # get*info()
+ assert(not VB_PATTERN.match(self.nodes[0].getinfo()["errors"]))
+ assert(not VB_PATTERN.match(self.nodes[0].getmininginfo()["errors"]))
+ assert(not VB_PATTERN.match(self.nodes[0].getnetworkinfo()["warnings"]))
# 3. Now build one period of blocks with >= VB_THRESHOLD blocks signaling
# some unknown bit
@@ -132,30 +99,31 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# Might not get a versionbits-related alert yet, as we should
# have gotten a different alert due to more than 51/100 blocks
# being of unexpected version.
- # Check that getinfo() shows some kind of error.
- assert(len(self.nodes[0].getinfo()["errors"]) != 0)
+ # Check that get*info() shows some kind of error.
+ assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getinfo()["errors"])
+ assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getmininginfo()["errors"])
+ assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getnetworkinfo()["warnings"])
# Mine a period worth of expected blocks so the generic block-version warning
# is cleared, and restart the node. This should move the versionbit state
# to ACTIVE.
self.nodes[0].generate(VB_PERIOD)
- stop_node(self.nodes[0], 0)
- wait_bitcoinds()
+ stop_nodes(self.nodes)
# Empty out the alert file
- with open(self.alert_filename, 'w') as f:
+ with open(self.alert_filename, 'w', encoding='utf8') as _:
pass
- self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""])
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
# Connecting one block should be enough to generate an error.
self.nodes[0].generate(1)
- assert(len(self.nodes[0].getinfo()["errors"]) != 0)
- stop_node(self.nodes[0], 0)
- wait_bitcoinds()
+ assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getinfo()["errors"])
+ assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getmininginfo()["errors"])
+ assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getnetworkinfo()["warnings"])
+ stop_nodes(self.nodes)
self.test_versionbits_in_alert_file()
# Test framework expects the node to still be running...
- self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""])
-
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
if __name__ == '__main__':
VersionBitsWarningTest().main()
diff --git a/test/functional/preciousblock.py b/test/functional/preciousblock.py
new file mode 100755
index 0000000000..04b41e76ba
--- /dev/null
+++ b/test/functional/preciousblock.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python3
+# Copyright (c) 2015-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.
+"""Test the preciousblock RPC."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ connect_nodes_bi,
+ sync_chain,
+ sync_blocks,
+)
+
+def unidirectional_node_sync_via_rpc(node_src, node_dest):
+ blocks_to_copy = []
+ blockhash = node_src.getbestblockhash()
+ while True:
+ try:
+ assert(len(node_dest.getblock(blockhash, False)) > 0)
+ break
+ except:
+ blocks_to_copy.append(blockhash)
+ blockhash = node_src.getblockheader(blockhash, True)['previousblockhash']
+ blocks_to_copy.reverse()
+ for blockhash in blocks_to_copy:
+ blockdata = node_src.getblock(blockhash, False)
+ assert(node_dest.submitblock(blockdata) in (None, 'inconclusive'))
+
+def node_sync_via_rpc(nodes):
+ for node_src in nodes:
+ for node_dest in nodes:
+ if node_src is node_dest:
+ continue
+ unidirectional_node_sync_via_rpc(node_src, node_dest)
+
+class PreciousTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+
+ def setup_network(self):
+ self.setup_nodes()
+
+ def run_test(self):
+ self.log.info("Ensure submitblock can in principle reorg to a competing chain")
+ self.nodes[0].generate(1)
+ assert_equal(self.nodes[0].getblockcount(), 1)
+ (hashY, hashZ) = self.nodes[1].generate(2)
+ assert_equal(self.nodes[1].getblockcount(), 2)
+ node_sync_via_rpc(self.nodes[0:3])
+ assert_equal(self.nodes[0].getbestblockhash(), hashZ)
+
+ self.log.info("Mine blocks A-B-C on Node 0")
+ (hashA, hashB, hashC) = self.nodes[0].generate(3)
+ assert_equal(self.nodes[0].getblockcount(), 5)
+ self.log.info("Mine competing blocks E-F-G on Node 1")
+ (hashE, hashF, hashG) = self.nodes[1].generate(3)
+ assert_equal(self.nodes[1].getblockcount(), 5)
+ assert(hashC != hashG)
+ self.log.info("Connect nodes and check no reorg occurs")
+ # Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync)
+ node_sync_via_rpc(self.nodes[0:2])
+ connect_nodes_bi(self.nodes,0,1)
+ assert_equal(self.nodes[0].getbestblockhash(), hashC)
+ assert_equal(self.nodes[1].getbestblockhash(), hashG)
+ self.log.info("Make Node0 prefer block G")
+ self.nodes[0].preciousblock(hashG)
+ assert_equal(self.nodes[0].getbestblockhash(), hashG)
+ self.log.info("Make Node0 prefer block C again")
+ self.nodes[0].preciousblock(hashC)
+ assert_equal(self.nodes[0].getbestblockhash(), hashC)
+ self.log.info("Make Node1 prefer block C")
+ self.nodes[1].preciousblock(hashC)
+ sync_chain(self.nodes[0:2]) # wait because node 1 may not have downloaded hashC
+ assert_equal(self.nodes[1].getbestblockhash(), hashC)
+ self.log.info("Make Node1 prefer block G again")
+ self.nodes[1].preciousblock(hashG)
+ assert_equal(self.nodes[1].getbestblockhash(), hashG)
+ self.log.info("Make Node0 prefer block G again")
+ self.nodes[0].preciousblock(hashG)
+ assert_equal(self.nodes[0].getbestblockhash(), hashG)
+ self.log.info("Make Node1 prefer block C again")
+ self.nodes[1].preciousblock(hashC)
+ assert_equal(self.nodes[1].getbestblockhash(), hashC)
+ self.log.info("Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
+ self.nodes[0].generate(1)
+ assert_equal(self.nodes[0].getblockcount(), 6)
+ sync_blocks(self.nodes[0:2])
+ hashH = self.nodes[0].getbestblockhash()
+ assert_equal(self.nodes[1].getbestblockhash(), hashH)
+ self.log.info("Node1 should not be able to prefer block C anymore")
+ self.nodes[1].preciousblock(hashC)
+ assert_equal(self.nodes[1].getbestblockhash(), hashH)
+ self.log.info("Mine competing blocks I-J-K-L on Node 2")
+ self.nodes[2].generate(4)
+ assert_equal(self.nodes[2].getblockcount(), 6)
+ hashL = self.nodes[2].getbestblockhash()
+ self.log.info("Connect nodes and check no reorg occurs")
+ node_sync_via_rpc(self.nodes[1:3])
+ connect_nodes_bi(self.nodes,1,2)
+ connect_nodes_bi(self.nodes,0,2)
+ assert_equal(self.nodes[0].getbestblockhash(), hashH)
+ assert_equal(self.nodes[1].getbestblockhash(), hashH)
+ assert_equal(self.nodes[2].getbestblockhash(), hashL)
+ self.log.info("Make Node1 prefer block L")
+ self.nodes[1].preciousblock(hashL)
+ assert_equal(self.nodes[1].getbestblockhash(), hashL)
+ self.log.info("Make Node2 prefer block H")
+ self.nodes[2].preciousblock(hashH)
+ assert_equal(self.nodes[2].getbestblockhash(), hashH)
+
+if __name__ == '__main__':
+ PreciousTest().main()
diff --git a/qa/rpc-tests/prioritise_transaction.py b/test/functional/prioritise_transaction.py
index e1771231c0..a07923edba 100755
--- a/qa/rpc-tests/prioritise_transaction.py
+++ b/test/functional/prioritise_transaction.py
@@ -2,14 +2,11 @@
# Copyright (c) 2015-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.
-
-#
-# Test PrioritiseTransaction code
-#
+"""Test the prioritisetransaction mining RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-from test_framework.mininode import COIN, MAX_BLOCK_SIZE
+from test_framework.mininode import COIN, MAX_BLOCK_BASE_SIZE
class PrioritiseTransactionTest(BitcoinTestFramework):
@@ -17,17 +14,12 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
+ self.extra_args = [["-printpriority=1"]]
+ def run_test(self):
self.txouts = gen_return_txouts()
-
- def setup_network(self):
- self.nodes = []
- self.is_network_split = False
-
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-printpriority=1"]))
self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
- def run_test(self):
utxo_count = 90
utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], utxo_count)
base_fee = self.relayfee*100 # our transactions are smaller than 100kb
@@ -39,10 +31,10 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
txids.append([])
start_range = i * range_size
end_range = start_range + range_size
- txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[start_range:end_range], (i+1)*base_fee)
+ txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[start_range:end_range], end_range - start_range, (i+1)*base_fee)
# Make sure that the size of each group of transactions exceeds
- # MAX_BLOCK_SIZE -- otherwise the test needs to be revised to create
+ # MAX_BLOCK_BASE_SIZE -- otherwise the test needs to be revised to create
# more transactions.
mempool = self.nodes[0].getrawmempool(True)
sizes = [0, 0, 0]
@@ -50,18 +42,16 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
for j in txids[i]:
assert(j in mempool)
sizes[i] += mempool[j]['size']
- assert(sizes[i] > MAX_BLOCK_SIZE) # Fail => raise utxo_count
+ assert(sizes[i] > MAX_BLOCK_BASE_SIZE) # Fail => raise utxo_count
# add a fee delta to something in the cheapest bucket and make sure it gets mined
- # also check that a different entry in the cheapest bucket is NOT mined (lower
- # the priority to ensure its not mined due to priority)
- self.nodes[0].prioritisetransaction(txids[0][0], 0, int(3*base_fee*COIN))
- self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0)
+ # also check that a different entry in the cheapest bucket is NOT mined
+ self.nodes[0].prioritisetransaction(txids[0][0], int(3*base_fee*COIN))
self.nodes[0].generate(1)
mempool = self.nodes[0].getrawmempool()
- print("Assert that prioritised transaction was mined")
+ self.log.info("Assert that prioritised transaction was mined")
assert(txids[0][0] not in mempool)
assert(txids[0][1] in mempool)
@@ -75,7 +65,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# Add a prioritisation before a tx is in the mempool (de-prioritising a
# high-fee transaction so that it's now low fee).
- self.nodes[0].prioritisetransaction(high_fee_tx, -1e15, -int(2*base_fee*COIN))
+ self.nodes[0].prioritisetransaction(high_fee_tx, -int(2*base_fee*COIN))
# Add everything back to mempool
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
@@ -93,13 +83,13 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# High fee transaction should not have been mined, but other high fee rate
# transactions should have been.
mempool = self.nodes[0].getrawmempool()
- print("Assert that de-prioritised transaction is still in mempool")
+ self.log.info("Assert that de-prioritised transaction is still in mempool")
assert(high_fee_tx in mempool)
for x in txids[2]:
if (x != high_fee_tx):
assert(x not in mempool)
- # Create a free, low priority transaction. Should be rejected.
+ # Create a free transaction. Should be rejected.
utxo_list = self.nodes[0].listunspent()
assert(len(utxo_list) > 0)
utxo = utxo_list[0]
@@ -107,37 +97,23 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
inputs = []
outputs = {}
inputs.append({"txid" : utxo["txid"], "vout" : utxo["vout"]})
- outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee
+ outputs[self.nodes[0].getnewaddress()] = utxo["amount"]
raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"]
- txid = self.nodes[0].sendrawtransaction(tx_hex)
+ tx_id = self.nodes[0].decoderawtransaction(tx_hex)["txid"]
- # A tx that spends an in-mempool tx has 0 priority, so we can use it to
- # test the effect of using prioritise transaction for mempool acceptance
- inputs = []
- inputs.append({"txid": txid, "vout": 0})
- outputs = {}
- outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee
- raw_tx2 = self.nodes[0].createrawtransaction(inputs, outputs)
- tx2_hex = self.nodes[0].signrawtransaction(raw_tx2)["hex"]
- tx2_id = self.nodes[0].decoderawtransaction(tx2_hex)["txid"]
-
- try:
- self.nodes[0].sendrawtransaction(tx2_hex)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- assert(tx2_id not in self.nodes[0].getrawmempool())
- else:
- assert(False)
+ # This will raise an exception due to min relay fee not being met
+ assert_raises_jsonrpc(-26, "66: min relay fee not met", self.nodes[0].sendrawtransaction, tx_hex)
+ assert(tx_id not in self.nodes[0].getrawmempool())
# This is a less than 1000-byte transaction, so just set the fee
# to be the minimum for a 1000 byte transaction and check that it is
# accepted.
- self.nodes[0].prioritisetransaction(tx2_id, 0, int(self.relayfee*COIN))
+ self.nodes[0].prioritisetransaction(tx_id, int(self.relayfee*COIN))
- print("Assert that prioritised free transaction is accepted to mempool")
- assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id)
- assert(tx2_id in self.nodes[0].getrawmempool())
+ self.log.info("Assert that prioritised free transaction is accepted to mempool")
+ assert_equal(self.nodes[0].sendrawtransaction(tx_hex), tx_id)
+ assert(tx_id in self.nodes[0].getrawmempool())
if __name__ == '__main__':
PrioritiseTransactionTest().main()
diff --git a/qa/rpc-tests/proxy_test.py b/test/functional/proxy_test.py
index 27160cae07..69384d9d85 100755
--- a/qa/rpc-tests/proxy_test.py
+++ b/test/functional/proxy_test.py
@@ -2,14 +2,8 @@
# Copyright (c) 2015-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.
+"""Test bitcoind with different proxy configuration.
-import socket
-
-from test_framework.socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.netutil import test_ipv6_local
-'''
Test plan:
- Start bitcoind's with different proxy configurations
- Use addnode to initiate connections
@@ -31,7 +25,22 @@ addnode connect to IPv4
addnode connect to IPv6
addnode connect to onion
addnode connect to generic DNS name
-'''
+"""
+
+import socket
+import os
+
+from test_framework.socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ PORT_MIN,
+ PORT_RANGE,
+ start_nodes,
+ assert_equal,
+)
+from test_framework.netutil import test_ipv6_local
+
+RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports
class ProxyTest(BitcoinTestFramework):
@@ -40,27 +49,28 @@ class ProxyTest(BitcoinTestFramework):
self.num_nodes = 4
self.setup_clean_chain = False
+ def setup_nodes(self):
self.have_ipv6 = test_ipv6_local()
# Create two proxies on different ports
# ... one unauthenticated
self.conf1 = Socks5Configuration()
- self.conf1.addr = ('127.0.0.1', 13000 + (os.getpid() % 1000))
+ self.conf1.addr = ('127.0.0.1', RANGE_BEGIN + (os.getpid() % 1000))
self.conf1.unauth = True
self.conf1.auth = False
# ... one supporting authenticated and unauthenticated (Tor)
self.conf2 = Socks5Configuration()
- self.conf2.addr = ('127.0.0.1', 14000 + (os.getpid() % 1000))
+ self.conf2.addr = ('127.0.0.1', RANGE_BEGIN + 1000 + (os.getpid() % 1000))
self.conf2.unauth = True
self.conf2.auth = True
if self.have_ipv6:
# ... one on IPv6 with similar configuration
self.conf3 = Socks5Configuration()
self.conf3.af = socket.AF_INET6
- self.conf3.addr = ('::1', 15000 + (os.getpid() % 1000))
+ self.conf3.addr = ('::1', RANGE_BEGIN + 2000 + (os.getpid() % 1000))
self.conf3.unauth = True
self.conf3.auth = True
else:
- print("Warning: testing without local IPv6 support")
+ self.log.warning("Testing without local IPv6 support")
self.serv1 = Socks5Server(self.conf1)
self.serv1.start()
@@ -70,18 +80,17 @@ class ProxyTest(BitcoinTestFramework):
self.serv3 = Socks5Server(self.conf3)
self.serv3.start()
- def setup_nodes(self):
# Note: proxies are not used to connect to local nodes
# this is because the proxy to use is based on CService.GetNetwork(), which return NET_UNROUTABLE for localhost
args = [
- ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'],
- ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'],
- ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'],
+ ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'],
+ ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'],
+ ['-listen', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'],
[]
]
if self.have_ipv6:
- args[3] = ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
- return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args)
+ args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args)
def node_test(self, node, proxies, auth, test_onion=True):
rv = []
diff --git a/qa/rpc-tests/pruning.py b/test/functional/pruning.py
index 7cbe69c29b..17019c658b 100755
--- a/qa/rpc-tests/pruning.py
+++ b/test/functional/pruning.py
@@ -2,17 +2,25 @@
# Copyright (c) 2014-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.
+"""Test the pruning code.
-#
-# Test pruning code
-# ********
-# WARNING:
-# This test uses 4GB of disk space.
-# This test takes 30 mins or more (up to 2 hours)
-# ********
+WARNING:
+This test uses 4GB of disk space.
+This test takes 30 mins or more (up to 2 hours)
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
+import time
+import os
+
+MIN_BLOCKS_TO_KEEP = 288
+
+# Rescans start at the earliest block up to 2 hours before a key timestamp, so
+# the manual prune RPC avoids pruning blocks in the same window to be
+# compatible with pruning based on key creation time.
+TIMESTAMP_WINDOW = 2 * 60 * 60
+
def calc_usage(blockdir):
return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(blockdir+f)) / (1024. * 1024.)
@@ -22,34 +30,30 @@ class PruneTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.setup_clean_chain = True
- self.num_nodes = 3
-
- self.utxo = []
- self.address = ["",""]
- self.txouts = gen_return_txouts()
+ self.num_nodes = 6
+
+ # Create nodes 0 and 1 to mine.
+ # Create node 2 to test pruning.
+ # Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later)
+ # Create nodes 5 to test wallet in prune mode, but do not connect
+ self.extra_args = [["-maxreceivebuffer=20000", "-blockmaxsize=999000", "-checkblocks=5"],
+ ["-maxreceivebuffer=20000", "-blockmaxsize=999000", "-checkblocks=5"],
+ ["-maxreceivebuffer=20000", "-prune=550"],
+ ["-maxreceivebuffer=20000", "-blockmaxsize=999000"],
+ ["-maxreceivebuffer=20000", "-blockmaxsize=999000"],
+ ["-prune=550"]]
def setup_network(self):
- self.nodes = []
- self.is_network_split = False
-
- # Create nodes 0 and 1 to mine
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900))
+ self.setup_nodes()
- # Create node 2 to test pruning
- self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-prune=550"], timewait=900))
- self.prunedir = self.options.tmpdir+"/node2/regtest/blocks/"
-
- self.address[0] = self.nodes[0].getnewaddress()
- self.address[1] = self.nodes[1].getnewaddress()
-
- # Determine default relay fee
- self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
+ self.prunedir = self.options.tmpdir + "/node2/regtest/blocks/"
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[1], 2)
connect_nodes(self.nodes[2], 0)
- sync_blocks(self.nodes[0:3])
+ connect_nodes(self.nodes[0], 3)
+ connect_nodes(self.nodes[0], 4)
+ sync_blocks(self.nodes[0:5])
def create_big_chain(self):
# Start by creating some coinbases we can spend later
@@ -58,19 +62,19 @@ class PruneTest(BitcoinTestFramework):
self.nodes[0].generate(150)
# Then mine enough full blocks to create more than 550MiB of data
for i in range(645):
- self.mine_full_block(self.nodes[0], self.address[0])
+ mine_large_block(self.nodes[0], self.utxo_cache_0)
- sync_blocks(self.nodes[0:3])
+ sync_blocks(self.nodes[0:5])
def test_height_min(self):
if not os.path.isfile(self.prunedir+"blk00000.dat"):
raise AssertionError("blk00000.dat is missing, pruning too early")
- print("Success")
- print("Though we're already using more than 550MiB, current usage:", calc_usage(self.prunedir))
- print("Mining 25 more blocks should cause the first block file to be pruned")
+ self.log.info("Success")
+ self.log.info("Though we're already using more than 550MiB, current usage: %d" % calc_usage(self.prunedir))
+ self.log.info("Mining 25 more blocks should cause the first block file to be pruned")
# Pruning doesn't run until we're allocating another chunk, 20 full blocks past the height cutoff will ensure this
for i in range(25):
- self.mine_full_block(self.nodes[0],self.address[0])
+ mine_large_block(self.nodes[0], self.utxo_cache_0)
waitstart = time.time()
while os.path.isfile(self.prunedir+"blk00000.dat"):
@@ -78,56 +82,54 @@ class PruneTest(BitcoinTestFramework):
if time.time() - waitstart > 30:
raise AssertionError("blk00000.dat not pruned when it should be")
- print("Success")
+ self.log.info("Success")
usage = calc_usage(self.prunedir)
- print("Usage should be below target:", usage)
+ self.log.info("Usage should be below target: %d" % usage)
if (usage > 550):
raise AssertionError("Pruning target not being met")
def create_chain_with_staleblocks(self):
# Create stale blocks in manageable sized chunks
- print("Mine 24 (stale) blocks on Node 1, followed by 25 (main chain) block reorg from Node 0, for 12 rounds")
+ self.log.info("Mine 24 (stale) blocks on Node 1, followed by 25 (main chain) block reorg from Node 0, for 12 rounds")
for j in range(12):
# Disconnect node 0 so it can mine a longer reorg chain without knowing about node 1's soon-to-be-stale chain
# Node 2 stays connected, so it hears about the stale blocks and then reorg's when node0 reconnects
# Stopping node 0 also clears its mempool, so it doesn't have node1's transactions to accidentally mine
- stop_node(self.nodes[0],0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)
+ self.stop_node(0)
+ self.nodes[0]=start_node(0, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)
# Mine 24 blocks in node 1
- self.utxo = self.nodes[1].listunspent()
for i in range(24):
if j == 0:
- self.mine_full_block(self.nodes[1],self.address[1])
+ mine_large_block(self.nodes[1], self.utxo_cache_1)
else:
self.nodes[1].generate(1) #tx's already in mempool from previous disconnects
# Reorg back with 25 block chain from node 0
- self.utxo = self.nodes[0].listunspent()
for i in range(25):
- self.mine_full_block(self.nodes[0],self.address[0])
+ mine_large_block(self.nodes[0], self.utxo_cache_0)
# Create connections in the order so both nodes can see the reorg at the same time
connect_nodes(self.nodes[1], 0)
connect_nodes(self.nodes[2], 0)
sync_blocks(self.nodes[0:3])
- print("Usage can be over target because of high stale rate:", calc_usage(self.prunedir))
+ self.log.info("Usage can be over target because of high stale rate: %d" % calc_usage(self.prunedir))
def reorg_test(self):
# Node 1 will mine a 300 block chain starting 287 blocks back from Node 0 and Node 2's tip
# This will cause Node 2 to do a reorg requiring 288 blocks of undo data to the reorg_test chain
# Reboot node 1 to clear its mempool (hopefully make the invalidate faster)
# Lower the block max size so we don't keep mining all our big mempool transactions (from disconnected blocks)
- stop_node(self.nodes[1],1)
- self.nodes[1]=start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
+ self.stop_node(1)
+ self.nodes[1]=start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
height = self.nodes[1].getblockcount()
- print("Current block height:", height)
+ self.log.info("Current block height: %d" % height)
invalidheight = height-287
badhash = self.nodes[1].getblockhash(invalidheight)
- print("Invalidating block at height:",invalidheight,badhash)
+ self.log.info("Invalidating block %s at height %d" % (badhash,invalidheight))
self.nodes[1].invalidateblock(badhash)
# We've now switched to our previously mined-24 block fork on node 1, but thats not what we want
@@ -139,29 +141,32 @@ class PruneTest(BitcoinTestFramework):
curhash = self.nodes[1].getblockhash(invalidheight - 1)
assert(self.nodes[1].getblockcount() == invalidheight - 1)
- print("New best height", self.nodes[1].getblockcount())
+ self.log.info("New best height: %d" % self.nodes[1].getblockcount())
# Reboot node1 to clear those giant tx's from mempool
- stop_node(self.nodes[1],1)
- self.nodes[1]=start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
+ self.stop_node(1)
+ self.nodes[1]=start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
- print("Generating new longer chain of 300 more blocks")
+ self.log.info("Generating new longer chain of 300 more blocks")
self.nodes[1].generate(300)
- print("Reconnect nodes")
+ self.log.info("Reconnect nodes")
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[2], 1)
sync_blocks(self.nodes[0:3], timeout=120)
- print("Verify height on node 2:",self.nodes[2].getblockcount())
- print("Usage possibly still high bc of stale blocks in block files:", calc_usage(self.prunedir))
+ self.log.info("Verify height on node 2: %d" % self.nodes[2].getblockcount())
+ self.log.info("Usage possibly still high bc of stale blocks in block files: %d" % calc_usage(self.prunedir))
- print("Mine 220 more blocks so we have requisite history (some blocks will be big and cause pruning of previous chain)")
- self.nodes[0].generate(220) #node 0 has many large tx's in its mempool from the disconnects
+ self.log.info("Mine 220 more blocks so we have requisite history (some blocks will be big and cause pruning of previous chain)")
+ for i in range(22):
+ # This can be slow, so do this in multiple RPC calls to avoid
+ # RPC timeouts.
+ self.nodes[0].generate(10) #node 0 has many large tx's in its mempool from the disconnects
sync_blocks(self.nodes[0:3], timeout=300)
usage = calc_usage(self.prunedir)
- print("Usage should be below target:", usage)
+ self.log.info("Usage should be below target: %d" % usage)
if (usage > 550):
raise AssertionError("Pruning target not being met")
@@ -169,11 +174,8 @@ class PruneTest(BitcoinTestFramework):
def reorg_back(self):
# Verify that a block on the old main chain fork has been pruned away
- try:
- self.nodes[2].getblock(self.forkhash)
- raise AssertionError("Old block wasn't pruned so can't test redownload")
- except JSONRPCException as e:
- print("Will need to redownload block",self.forkheight)
+ assert_raises_jsonrpc(-1, "Block not available (pruned data)", self.nodes[2].getblock, self.forkhash)
+ self.log.info("Will need to redownload block %d" % self.forkheight)
# Verify that we have enough history to reorg back to the fork point
# Although this is more than 288 blocks, because this chain was written more recently
@@ -197,14 +199,14 @@ class PruneTest(BitcoinTestFramework):
# At this point node 2 is within 288 blocks of the fork point so it will preserve its ability to reorg
if self.nodes[2].getblockcount() < self.mainchainheight:
blocks_to_mine = first_reorg_height + 1 - self.mainchainheight
- print("Rewind node 0 to prev main chain to mine longer chain to trigger redownload. Blocks needed:", blocks_to_mine)
+ self.log.info("Rewind node 0 to prev main chain to mine longer chain to trigger redownload. Blocks needed: %d" % blocks_to_mine)
self.nodes[0].invalidateblock(curchainhash)
assert(self.nodes[0].getblockcount() == self.mainchainheight)
assert(self.nodes[0].getbestblockhash() == self.mainchainhash2)
goalbesthash = self.nodes[0].generate(blocks_to_mine)[-1]
goalbestheight = first_reorg_height + 1
- print("Verify node 2 reorged back to the main chain, some blocks of which it had to redownload")
+ self.log.info("Verify node 2 reorged back to the main chain, some blocks of which it had to redownload")
waitstart = time.time()
while self.nodes[2].getblockcount() < goalbestheight:
time.sleep(0.1)
@@ -214,35 +216,120 @@ class PruneTest(BitcoinTestFramework):
# Verify we can now have the data for a block previously pruned
assert(self.nodes[2].getblock(self.forkhash)["height"] == self.forkheight)
- def mine_full_block(self, node, address):
- # Want to create a full block
- # We'll generate a 66k transaction below, and 14 of them is close to the 1MB block limit
- for j in range(14):
- if len(self.utxo) < 14:
- self.utxo = node.listunspent()
- inputs=[]
- outputs = {}
- t = self.utxo.pop()
- inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
- remchange = t["amount"] - 100*self.relayfee # Fee must be above min relay rate for 66kb tx
- outputs[address]=remchange
- # Create a basic transaction that will send change back to ourself after account for a fee
- # And then insert the 128 generated transaction outs in the middle rawtx[92] is where the #
- # of txouts is stored and is the only thing we overwrite from the original transaction
- rawtx = node.createrawtransaction(inputs, outputs)
- newtx = rawtx[0:92]
- newtx = newtx + self.txouts
- newtx = newtx + rawtx[94:]
- # Appears to be ever so slightly faster to sign with SIGHASH_NONE
- signresult = node.signrawtransaction(newtx,None,None,"NONE")
- txid = node.sendrawtransaction(signresult["hex"], True)
- # Mine a full sized block which will be these transactions we just created
- node.generate(1)
-
+ def manual_test(self, node_number, use_timestamp):
+ # at this point, node has 995 blocks and has not yet run in prune mode
+ node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, timewait=900)
+ assert_equal(node.getblockcount(), 995)
+ assert_raises_jsonrpc(-1, "not in prune mode", node.pruneblockchain, 500)
+ self.stop_node(node_number)
+
+ # now re-start in manual pruning mode
+ node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-prune=1"], timewait=900)
+ assert_equal(node.getblockcount(), 995)
+
+ def height(index):
+ if use_timestamp:
+ return node.getblockheader(node.getblockhash(index))["time"] + TIMESTAMP_WINDOW
+ else:
+ return index
+
+ def prune(index, expected_ret=None):
+ ret = node.pruneblockchain(height(index))
+ # Check the return value. When use_timestamp is True, just check
+ # that the return value is less than or equal to the expected
+ # value, because when more than one block is generated per second,
+ # a timestamp will not be granular enough to uniquely identify an
+ # individual block.
+ if expected_ret is None:
+ expected_ret = index
+ if use_timestamp:
+ assert_greater_than(ret, 0)
+ assert_greater_than(expected_ret + 1, ret)
+ else:
+ assert_equal(ret, expected_ret)
+
+ def has_block(index):
+ return os.path.isfile(self.options.tmpdir + "/node{}/regtest/blocks/blk{:05}.dat".format(node_number, index))
+
+ # should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000)
+ assert_raises_jsonrpc(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500))
+
+ # mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight)
+ node.generate(6)
+ assert_equal(node.getblockchaininfo()["blocks"], 1001)
+
+ # negative heights should raise an exception
+ assert_raises_jsonrpc(-8, "Negative", node.pruneblockchain, -10)
+
+ # height=100 too low to prune first block file so this is a no-op
+ prune(100)
+ if not has_block(0):
+ raise AssertionError("blk00000.dat is missing when should still be there")
+
+ # Does nothing
+ node.pruneblockchain(height(0))
+ if not has_block(0):
+ raise AssertionError("blk00000.dat is missing when should still be there")
+
+ # height=500 should prune first file
+ prune(500)
+ if has_block(0):
+ raise AssertionError("blk00000.dat is still there, should be pruned by now")
+ if not has_block(1):
+ raise AssertionError("blk00001.dat is missing when should still be there")
+
+ # height=650 should prune second file
+ prune(650)
+ if has_block(1):
+ raise AssertionError("blk00001.dat is still there, should be pruned by now")
+
+ # height=1000 should not prune anything more, because tip-288 is in blk00002.dat.
+ prune(1000, 1001 - MIN_BLOCKS_TO_KEEP)
+ if not has_block(2):
+ raise AssertionError("blk00002.dat is still there, should be pruned by now")
+
+ # advance the tip so blk00002.dat and blk00003.dat can be pruned (the last 288 blocks should now be in blk00004.dat)
+ node.generate(288)
+ prune(1000)
+ if has_block(2):
+ raise AssertionError("blk00002.dat is still there, should be pruned by now")
+ if has_block(3):
+ raise AssertionError("blk00003.dat is still there, should be pruned by now")
+
+ # stop node, start back up with auto-prune at 550MB, make sure still runs
+ self.stop_node(node_number)
+ self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-prune=550"], timewait=900)
+
+ self.log.info("Success")
+
+ def wallet_test(self):
+ # check that the pruning node's wallet is still in good shape
+ self.log.info("Stop and start pruning node to trigger wallet rescan")
+ self.stop_node(2)
+ start_node(2, self.options.tmpdir, ["-prune=550"])
+ self.log.info("Success")
+
+ # check that wallet loads loads successfully when restarting a pruned node after IBD.
+ # this was reported to fail in #7494.
+ self.log.info("Syncing node 5 to test wallet")
+ connect_nodes(self.nodes[0], 5)
+ nds = [self.nodes[0], self.nodes[5]]
+ sync_blocks(nds, wait=5, timeout=300)
+ self.stop_node(5) #stop and start to trigger rescan
+ start_node(5, self.options.tmpdir, ["-prune=550"])
+ self.log.info("Success")
def run_test(self):
- print("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)")
- print("Mining a big blockchain of 995 blocks")
+ self.log.info("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)")
+ self.log.info("Mining a big blockchain of 995 blocks")
+
+ # Determine default relay fee
+ self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
+
+ # Cache for utxos, as the listunspent may take a long time later in the test
+ self.utxo_cache_0 = []
+ self.utxo_cache_1 = []
+
self.create_big_chain()
# Chain diagram key:
# * blocks on main chain
@@ -253,12 +340,16 @@ class PruneTest(BitcoinTestFramework):
# Start by mining a simple chain that all nodes have
# N0=N1=N2 **...*(995)
- print("Check that we haven't started pruning yet because we're below PruneAfterHeight")
+ # stop manual-pruning node with 995 blocks
+ self.stop_node(3)
+ self.stop_node(4)
+
+ self.log.info("Check that we haven't started pruning yet because we're below PruneAfterHeight")
self.test_height_min()
# Extend this chain past the PruneAfterHeight
# N0=N1=N2 **...*(1020)
- print("Check that we'll exceed disk space target if we have a very high stale block rate")
+ self.log.info("Check that we'll exceed disk space target if we have a very high stale block rate")
self.create_chain_with_staleblocks()
# Disconnect N0
# And mine a 24 block chain on N1 and a separate 25 block chain on N0
@@ -282,7 +373,7 @@ class PruneTest(BitcoinTestFramework):
self.mainchainheight = self.nodes[2].getblockcount() #1320
self.mainchainhash2 = self.nodes[2].getblockhash(self.mainchainheight)
- print("Check that we can survive a 288 block reorg still")
+ self.log.info("Check that we can survive a 288 block reorg still")
(self.forkheight,self.forkhash) = self.reorg_test() #(1033, )
# Now create a 288 block reorg by mining a longer chain on N1
# First disconnect N1
@@ -315,7 +406,7 @@ class PruneTest(BitcoinTestFramework):
# \
# *...**(1320)
- print("Test that we can rerequest a block we previously pruned if needed for a reorg")
+ self.log.info("Test that we can rerequest a block we previously pruned if needed for a reorg")
self.reorg_back()
# Verify that N2 still has block 1033 on current chain (@), but not on main chain (*)
# Invalidate 1033 on current chain (@) on N2 and we should be able to reorg to
@@ -335,7 +426,16 @@ class PruneTest(BitcoinTestFramework):
#
# N1 doesn't change because 1033 on main chain (*) is invalid
- print("Done")
+ self.log.info("Test manual pruning with block indices")
+ self.manual_test(3, use_timestamp=False)
+
+ self.log.info("Test manual pruning with timestamps")
+ self.manual_test(4, use_timestamp=True)
+
+ self.log.info("Test wallet re-scan")
+ self.wallet_test()
+
+ self.log.info("Done")
if __name__ == '__main__':
PruneTest().main()
diff --git a/qa/rpc-tests/rawtransactions.py b/test/functional/rawtransactions.py
index ab6d2e8def..35debf9cab 100755
--- a/qa/rpc-tests/rawtransactions.py
+++ b/test/functional/rawtransactions.py
@@ -2,11 +2,15 @@
# Copyright (c) 2014-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.
+"""Test the rawtranscation RPCs.
-#
-# Test re-org scenarios with a mempool that contains transactions
-# that spend (directly or indirectly) coinbase transactions.
-#
+Test the following RPCs:
+ - createrawtransaction
+ - signrawtransaction
+ - sendrawtransaction
+ - decoderawtransaction
+ - getrawtransaction
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -20,21 +24,9 @@ class RawTransactionsTest(BitcoinTestFramework):
self.num_nodes = 3
def setup_network(self, split=False):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
-
- #connect to a local machine for debugging
- #url = "http://bitcoinrpc:DP6DvqZtqXarpeNWyN3LZTFchCCyCUuHwNF7E8pX99x1@%s:%d" % ('127.0.0.1', 18332)
- #proxy = AuthServiceProxy(url)
- #proxy.url = url # store URL on proxy for info
- #self.nodes.append(proxy)
-
- connect_nodes_bi(self.nodes,0,1)
- connect_nodes_bi(self.nodes,1,2)
+ super().setup_network()
connect_nodes_bi(self.nodes,0,2)
- self.is_network_split=False
- self.sync_all()
-
def run_test(self):
#prepare some coins for multiple *rawtransaction commands
@@ -57,13 +49,8 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
rawtx = self.nodes[2].signrawtransaction(rawtx)
- try:
- rawtx = self.nodes[2].sendrawtransaction(rawtx['hex'])
- except JSONRPCException as e:
- assert("Missing inputs" in e.error['message'])
- else:
- assert(False)
-
+ # This will raise an exception since there are missing inputs
+ assert_raises_jsonrpc(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex'])
#########################
# RAW TX MULTISIG TESTS #
@@ -105,7 +92,6 @@ class RawTransactionsTest(BitcoinTestFramework):
txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
decTx = self.nodes[0].gettransaction(txId)
rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
- sPK = rawTx['vout'][0]['scriptPubKey']['hex']
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
@@ -138,19 +124,48 @@ class RawTransactionsTest(BitcoinTestFramework):
self.sync_all()
assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx
+ # getrawtransaction tests
+ # 1. valid parameters - only supply txid
+ txHash = rawTx["hash"]
+ assert_equal(self.nodes[0].getrawtransaction(txHash), rawTxSigned['hex'])
+
+ # 2. valid parameters - supply txid and 0 for non-verbose
+ assert_equal(self.nodes[0].getrawtransaction(txHash, 0), rawTxSigned['hex'])
+
+ # 3. valid parameters - supply txid and False for non-verbose
+ assert_equal(self.nodes[0].getrawtransaction(txHash, False), rawTxSigned['hex'])
+
+ # 4. valid parameters - supply txid and 1 for verbose.
+ # We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
+ assert_equal(self.nodes[0].getrawtransaction(txHash, 1)["hex"], rawTxSigned['hex'])
+
+ # 5. valid parameters - supply txid and True for non-verbose
+ assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex'])
+
+ # 6. invalid parameters - supply txid and string "Flase"
+ assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, "Flase")
+
+ # 7. invalid parameters - supply txid and empty array
+ assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, [])
+
+ # 8. invalid parameters - supply txid and empty dict
+ assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, {})
+
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}]
outputs = { self.nodes[0].getnewaddress() : 1 }
rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
decrawtx= self.nodes[0].decoderawtransaction(rawtx)
assert_equal(decrawtx['vin'][0]['sequence'], 1000)
+ # 9. invalid parameters - sequence number out of range
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : -1}]
outputs = { self.nodes[0].getnewaddress() : 1 }
- assert_raises(JSONRPCException, self.nodes[0].createrawtransaction, inputs, outputs)
+ assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)
+ # 10. invalid parameters - sequence number out of range
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967296}]
outputs = { self.nodes[0].getnewaddress() : 1 }
- assert_raises(JSONRPCException, self.nodes[0].createrawtransaction, inputs, outputs)
+ assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967294}]
outputs = { self.nodes[0].getnewaddress() : 1 }
diff --git a/qa/rpc-tests/receivedby.py b/test/functional/receivedby.py
index 4f17b661cb..a1cae301c5 100755
--- a/qa/rpc-tests/receivedby.py
+++ b/test/functional/receivedby.py
@@ -2,19 +2,16 @@
# Copyright (c) 2014-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.
-
-# Exercise the listreceivedbyaddress API
+"""Test the listreceivedbyaddress RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-
def get_sub_array_from_array(object_array, to_match):
'''
Finds and returns a sub array from an array of arrays.
to_match should be a unique idetifier of a sub array
'''
- num_matched = 0
for item in object_array:
all_match = True
for key,value in to_match.items():
@@ -35,7 +32,7 @@ class ReceivedByTest(BitcoinTestFramework):
def setup_nodes(self):
#This test requires mocktime
enable_mocktime()
- return start_nodes(self.num_nodes, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
'''
@@ -104,7 +101,7 @@ class ReceivedByTest(BitcoinTestFramework):
received_by_account_json = get_sub_array_from_array(self.nodes[1].listreceivedbyaccount(),{"account":account})
if len(received_by_account_json) == 0:
raise AssertionError("No accounts found in node")
- balance_by_account = rec_by_accountArr = self.nodes[1].getreceivedbyaccount(account)
+ balance_by_account = self.nodes[1].getreceivedbyaccount(account)
txid = self.nodes[0].sendtoaddress(addr, 0.1)
self.sync_all()
diff --git a/qa/rpc-tests/reindex.py b/test/functional/reindex.py
index abbbb10336..8b8c5f3e71 100755
--- a/qa/rpc-tests/reindex.py
+++ b/test/functional/reindex.py
@@ -2,12 +2,19 @@
# Copyright (c) 2014-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.
+"""Test running bitcoind with -reindex and -reindex-chainstate options.
+
+- Start a single node and generate 3 blocks.
+- Stop the node and restart it with -reindex. Verify that the node has reindexed up to block 3.
+- Stop the node and restart it with -reindex-chainstate. Verify that the node has reindexed up to block 3.
+"""
-#
-# Test -reindex and -reindex-chainstate with CheckBlockIndex
-#
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import (
+ start_nodes,
+ stop_nodes,
+ assert_equal,
+)
import time
class ReindexTest(BitcoinTestFramework):
@@ -17,21 +24,16 @@ class ReindexTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 1
- def setup_network(self):
- self.nodes = []
- self.is_network_split = False
- self.nodes.append(start_node(0, self.options.tmpdir))
-
def reindex(self, justchainstate=False):
self.nodes[0].generate(3)
blockcount = self.nodes[0].getblockcount()
- stop_node(self.nodes[0], 0)
- wait_bitcoinds()
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"])
+ stop_nodes(self.nodes)
+ extra_args = [["-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]]
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
while self.nodes[0].getblockcount() < blockcount:
time.sleep(0.1)
assert_equal(self.nodes[0].getblockcount(), blockcount)
- print("Success")
+ self.log.info("Success")
def run_test(self):
self.reindex(False)
diff --git a/qa/rpc-tests/replace-by-fee.py b/test/functional/replace-by-fee.py
index 34c0f9d795..e940ce535c 100755
--- a/qa/rpc-tests/replace-by-fee.py
+++ b/test/functional/replace-by-fee.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-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.
-
-#
-# Test replace by fee code
-#
+"""Test the RBF code."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -28,19 +25,15 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
fee = 1*COIN
while node.getbalance() < satoshi_round((amount + fee)/COIN):
node.generate(100)
- #print (node.getbalance(), amount, fee)
new_addr = node.getnewaddress()
- #print new_addr
txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN))
tx1 = node.getrawtransaction(txid, 1)
txid = int(txid, 16)
i = None
for i, txout in enumerate(tx1['vout']):
- #print i, txout['scriptPubKey']['addresses']
if txout['scriptPubKey']['addresses'] == [new_addr]:
- #print i
break
assert i is not None
@@ -72,49 +65,44 @@ class ReplaceByFeeTest(BitcoinTestFramework):
super().__init__()
self.num_nodes = 1
self.setup_clean_chain = False
-
- def setup_network(self):
- self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug",
- "-relaypriority=0", "-whitelist=127.0.0.1",
- "-limitancestorcount=50",
- "-limitancestorsize=101",
- "-limitdescendantcount=200",
- "-limitdescendantsize=101"
- ]))
- self.is_network_split = False
+ self.extra_args= [["-maxorphantx=1000",
+ "-whitelist=127.0.0.1",
+ "-limitancestorcount=50",
+ "-limitancestorsize=101",
+ "-limitdescendantcount=200",
+ "-limitdescendantsize=101"]]
def run_test(self):
make_utxo(self.nodes[0], 1*COIN)
- print("Running test simple doublespend...")
+ self.log.info("Running test simple doublespend...")
self.test_simple_doublespend()
- print("Running test doublespend chain...")
+ self.log.info("Running test doublespend chain...")
self.test_doublespend_chain()
- print("Running test doublespend tree...")
+ self.log.info("Running test doublespend tree...")
self.test_doublespend_tree()
- print("Running test replacement feeperkb...")
+ self.log.info("Running test replacement feeperkb...")
self.test_replacement_feeperkb()
- print("Running test spends of conflicting outputs...")
+ self.log.info("Running test spends of conflicting outputs...")
self.test_spends_of_conflicting_outputs()
- print("Running test new unconfirmed inputs...")
+ self.log.info("Running test new unconfirmed inputs...")
self.test_new_unconfirmed_inputs()
- print("Running test too many replacements...")
+ self.log.info("Running test too many replacements...")
self.test_too_many_replacements()
- print("Running test opt-in...")
+ self.log.info("Running test opt-in...")
self.test_opt_in()
- print("Running test prioritised transactions...")
+ self.log.info("Running test prioritised transactions...")
self.test_prioritised_transactions()
- print("Passed\n")
+ self.log.info("Passed")
def test_simple_doublespend(self):
"""Simple doublespend"""
@@ -132,12 +120,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b.vout = [CTxOut(1*COIN, CScript([b'b']))]
tx1b_hex = txToHex(tx1b)
- try:
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- else:
- assert(False)
+ # This will raise an exception due to insufficient fee
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True)
# Extra 0.1 BTC fee
tx1b = CTransaction()
@@ -179,12 +163,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx.vout = [CTxOut(initial_nValue - 30*COIN, CScript([1]))]
dbl_tx_hex = txToHex(dbl_tx)
- try:
- self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- else:
- assert(False) # transaction mistakenly accepted!
+ # This will raise an exception due to insufficient fee
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True)
# Accepted with sufficient fee
dbl_tx = CTransaction()
@@ -244,12 +224,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
dbl_tx.vout = [CTxOut(initial_nValue - fee*n, CScript([1]))]
dbl_tx_hex = txToHex(dbl_tx)
- try:
- self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- else:
- assert(False)
+ # This will raise an exception due to insufficient fee
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True)
# 1 BTC fee is enough
dbl_tx = CTransaction()
@@ -276,13 +252,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
dbl_tx.vout = [CTxOut(initial_nValue - 2*fee*n, CScript([1]))]
dbl_tx_hex = txToHex(dbl_tx)
- try:
- self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- assert_equal("too many potential replacements" in exp.error['message'], True)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, dbl_tx_hex, True)
for tx in tree_txs:
tx.rehash()
@@ -305,12 +276,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*999000]))]
tx1b_hex = txToHex(tx1b)
- try:
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- else:
- assert(False)
+ # This will raise an exception due to insufficient fee
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True)
def test_spends_of_conflicting_outputs(self):
"""Replacements that spend conflicting tx outputs are rejected"""
@@ -332,12 +299,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2.vout = tx1a.vout
tx2_hex = txToHex(tx2)
- try:
- tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True)
# Spend tx1a's output to test the indirect case.
tx1b = CTransaction()
@@ -353,12 +316,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2.vout = tx1a.vout
tx2_hex = txToHex(tx2)
- try:
- tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True)
def test_new_unconfirmed_inputs(self):
"""Replacements that add new unconfirmed inputs are rejected"""
@@ -376,12 +335,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2.vout = tx1.vout
tx2_hex = txToHex(tx2)
- try:
- tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "replacement-adds-unconfirmed", self.nodes[0].sendrawtransaction, tx2_hex, True)
def test_too_many_replacements(self):
"""Replacements that evict too many transactions are rejected"""
@@ -393,7 +348,6 @@ class ReplaceByFeeTest(BitcoinTestFramework):
utxo = make_utxo(self.nodes[0], initial_nValue)
fee = int(0.0001*COIN)
split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1))
- actual_fee = initial_nValue - split_value*(MAX_REPLACEMENT_LIMIT+1)
outputs = []
for i in range(MAX_REPLACEMENT_LIMIT+1):
@@ -427,13 +381,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))]
double_tx_hex = txToHex(double_tx)
- try:
- self.nodes[0].sendrawtransaction(double_tx_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- assert_equal("too many potential replacements" in exp.error['message'], True)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, double_tx_hex, True)
# If we remove an input, it should pass
double_tx = CTransaction()
@@ -443,7 +392,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
self.nodes[0].sendrawtransaction(double_tx_hex, True)
def test_opt_in(self):
- """ Replacing should only work if orig tx opted in """
+ """Replacing should only work if orig tx opted in"""
tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
# Create a non-opting in transaction
@@ -459,13 +408,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))]
tx1b_hex = txToHex(tx1b)
- try:
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- print(tx1b_txid)
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx1b_hex, True)
tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
@@ -482,12 +426,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))]
tx2b_hex = txToHex(tx2b)
- try:
- tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx2b_hex, True)
# Now create a new transaction that spends from tx1a and tx2a
# opt-in on one of the inputs
@@ -539,15 +479,10 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b_hex = txToHex(tx1b)
# Verify tx1b cannot replace tx1a.
- try:
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True)
# Use prioritisetransaction to set tx1a's fee to 0.
- self.nodes[0].prioritisetransaction(tx1a_txid, 0, int(-0.1*COIN))
+ self.nodes[0].prioritisetransaction(tx1a_txid, int(-0.1*COIN))
# Now tx1b should be able to replace tx1a
tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
@@ -571,15 +506,10 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2b_hex = txToHex(tx2b)
# Verify tx2b cannot replace tx2a.
- try:
- tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx2b_hex, True)
# Now prioritise tx2b to have a higher modified fee
- self.nodes[0].prioritisetransaction(tx2b.hash, 0, int(0.1*COIN))
+ self.nodes[0].prioritisetransaction(tx2b.hash, int(0.1*COIN))
# tx2b should now be accepted
tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
diff --git a/qa/rpc-tests/rest.py b/test/functional/rest.py
index c9c2eaf7f3..fbcceba0fa 100755
--- a/qa/rpc-tests/rest.py
+++ b/test/functional/rest.py
@@ -2,11 +2,7 @@
# Copyright (c) 2014-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.
-
-#
-# Test REST interface
-#
-
+"""Test the REST API."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -53,16 +49,12 @@ class RESTTest (BitcoinTestFramework):
self.num_nodes = 3
def setup_network(self, split=False):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
- connect_nodes_bi(self.nodes,0,1)
- connect_nodes_bi(self.nodes,1,2)
- connect_nodes_bi(self.nodes,0,2)
- self.is_network_split=False
- self.sync_all()
+ super().setup_network()
+ connect_nodes_bi(self.nodes, 0, 2)
def run_test(self):
url = urllib.parse.urlparse(self.nodes[0].url)
- print("Mining blocks...")
+ self.log.info("Mining blocks...")
self.nodes[0].generate(1)
self.sync_all()
@@ -179,14 +171,14 @@ class RESTTest (BitcoinTestFramework):
#do some invalid requests
json_request = '{"checkmempool'
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'json', json_request, True)
- assert_equal(response.status, 500) #must be a 500 because we send a invalid json request
+ assert_equal(response.status, 400) #must be a 400 because we send a invalid json request
json_request = '{"checkmempool'
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', json_request, True)
- assert_equal(response.status, 500) #must be a 500 because we send a invalid bin request
+ assert_equal(response.status, 400) #must be a 400 because we send a invalid bin request
response = http_post_call(url.hostname, url.port, '/rest/getutxos/checkmempool'+self.FORMAT_SEPARATOR+'bin', '', True)
- assert_equal(response.status, 500) #must be a 500 because we send a invalid bin request
+ assert_equal(response.status, 400) #must be a 400 because we send a invalid bin request
#test limits
json_request = '/checkmempool/'
@@ -194,14 +186,14 @@ class RESTTest (BitcoinTestFramework):
json_request += txid+'-'+str(n)+'/'
json_request = json_request.rstrip("/")
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True)
- assert_equal(response.status, 500) #must be a 500 because we exceeding the limits
+ assert_equal(response.status, 400) #must be a 400 because we exceeding the limits
json_request = '/checkmempool/'
for x in range(0, 15):
json_request += txid+'-'+str(n)+'/'
json_request = json_request.rstrip("/")
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True)
- assert_equal(response.status, 200) #must be a 500 because we exceeding the limits
+ assert_equal(response.status, 200) #must be a 200 because we are within the limits
self.nodes[0].generate(1) #generate block to not affect upcoming tests
self.sync_all()
diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py
new file mode 100755
index 0000000000..efc36481d1
--- /dev/null
+++ b/test/functional/rpcbind_test.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+"""Test running bitcoind with the -rpcbind and -rpcallowip options."""
+
+import socket
+import sys
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+from test_framework.netutil import *
+
+
+class RPCBindTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def setup_network(self):
+ pass
+
+ def setup_nodes(self):
+ pass
+
+ def run_bind_test(self, allow_ips, connect_to, addresses, expected):
+ '''
+ Start a node with requested rpcallowip and rpcbind parameters,
+ then try to connect, and check if the set of bound addresses
+ matches the expected set.
+ '''
+ expected = [(addr_to_hex(addr), port) for (addr, port) in expected]
+ base_args = ['-disablewallet', '-nolisten']
+ if allow_ips:
+ base_args += ['-rpcallowip=' + x for x in allow_ips]
+ binds = ['-rpcbind='+addr for addr in addresses]
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [base_args + binds], connect_to)
+ pid = bitcoind_processes[0].pid
+ assert_equal(set(get_bind_addrs(pid)), set(expected))
+ stop_nodes(self.nodes)
+
+ def run_allowip_test(self, allow_ips, rpchost, rpcport):
+ '''
+ Start a node with rpcallow IP, and request getnetworkinfo
+ at a non-localhost IP.
+ '''
+ base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [base_args])
+ # connect to node through non-loopback interface
+ node = get_rpc_proxy(rpc_url(0, "%s:%d" % (rpchost, rpcport)), 0)
+ node.getnetworkinfo()
+ stop_nodes(self.nodes)
+
+ def run_test(self):
+ # due to OS-specific network stats queries, this test works only on Linux
+ if not sys.platform.startswith('linux'):
+ self.log.warning("This test can only be run on linux. Skipping test.")
+ sys.exit(self.TEST_EXIT_SKIPPED)
+ # find the first non-loopback interface for testing
+ non_loopback_ip = None
+ for name,ip in all_interfaces():
+ if ip != '127.0.0.1':
+ non_loopback_ip = ip
+ break
+ if non_loopback_ip is None:
+ self.log.warning("This test requires at least one non-loopback IPv4 interface. Skipping test.")
+ sys.exit(self.TEST_EXIT_SKIPPED)
+ try:
+ s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
+ s.connect(("::1",1))
+ s.close
+ except OSError:
+ self.log.warning("This test requires IPv6 support. Skipping test.")
+ sys.exit(self.TEST_EXIT_SKIPPED)
+
+ self.log.info("Using interface %s for testing" % non_loopback_ip)
+
+ defaultport = rpc_port(0)
+
+ # check default without rpcallowip (IPv4 and IPv6 localhost)
+ self.run_bind_test(None, '127.0.0.1', [],
+ [('127.0.0.1', defaultport), ('::1', defaultport)])
+ # check default with rpcallowip (IPv6 any)
+ self.run_bind_test(['127.0.0.1'], '127.0.0.1', [],
+ [('::0', defaultport)])
+ # check only IPv4 localhost (explicit)
+ self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1'],
+ [('127.0.0.1', defaultport)])
+ # check only IPv4 localhost (explicit) with alternative port
+ self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171'],
+ [('127.0.0.1', 32171)])
+ # check only IPv4 localhost (explicit) with multiple alternative ports on same host
+ self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171', '127.0.0.1:32172'],
+ [('127.0.0.1', 32171), ('127.0.0.1', 32172)])
+ # check only IPv6 localhost (explicit)
+ self.run_bind_test(['[::1]'], '[::1]', ['[::1]'],
+ [('::1', defaultport)])
+ # check both IPv4 and IPv6 localhost (explicit)
+ self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1', '[::1]'],
+ [('127.0.0.1', defaultport), ('::1', defaultport)])
+ # check only non-loopback interface
+ self.run_bind_test([non_loopback_ip], non_loopback_ip, [non_loopback_ip],
+ [(non_loopback_ip, defaultport)])
+
+ # Check that with invalid rpcallowip, we are denied
+ self.run_allowip_test([non_loopback_ip], non_loopback_ip, defaultport)
+ assert_raises_jsonrpc(-342, "non-JSON HTTP response with '403 Forbidden' from server", self.run_allowip_test, ['1.1.1.1'], non_loopback_ip, defaultport)
+
+if __name__ == '__main__':
+ RPCBindTest().main()
diff --git a/test/functional/rpcnamedargs.py b/test/functional/rpcnamedargs.py
new file mode 100755
index 0000000000..3b286000a1
--- /dev/null
+++ b/test/functional/rpcnamedargs.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Test using named arguments for RPCs."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_jsonrpc,
+)
+
+
+class NamedArgumentTest(BitcoinTestFramework):
+ """
+ Test named arguments on RPC calls.
+ """
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = False
+ self.num_nodes = 1
+
+ def run_test(self):
+ node = self.nodes[0]
+ h = node.help(command='getinfo')
+ assert(h.startswith('getinfo\n'))
+
+ assert_raises_jsonrpc(-8, 'Unknown named parameter', node.help, random='getinfo')
+
+ h = node.getblockhash(height=0)
+ node.getblock(blockhash=h)
+
+ assert_equal(node.echo(), [])
+ assert_equal(node.echo(arg0=0,arg9=9), [0] + [None]*8 + [9])
+ assert_equal(node.echo(arg1=1), [None, 1])
+ assert_equal(node.echo(arg9=None), [None]*10)
+ assert_equal(node.echo(arg0=0,arg3=3,arg9=9), [0] + [None]*2 + [3] + [None]*5 + [9])
+
+if __name__ == '__main__':
+ NamedArgumentTest().main()
diff --git a/test/functional/segwit.py b/test/functional/segwit.py
new file mode 100755
index 0000000000..ac95d66466
--- /dev/null
+++ b/test/functional/segwit.py
@@ -0,0 +1,638 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Test the SegWit changeover logic."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+from test_framework.mininode import sha256, CTransaction, CTxIn, COutPoint, CTxOut, COIN, ToHex, FromHex
+from test_framework.address import script_to_p2sh, key_to_p2pkh
+from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG, OP_TRUE
+from io import BytesIO
+
+NODE_0 = 0
+NODE_1 = 1
+NODE_2 = 2
+WIT_V0 = 0
+WIT_V1 = 1
+
+# Create a scriptPubKey corresponding to either a P2WPKH output for the
+# given pubkey, or a P2WSH output of a 1-of-1 multisig for the given
+# pubkey. Returns the hex encoding of the scriptPubKey.
+def witness_script(use_p2wsh, pubkey):
+ if (use_p2wsh == False):
+ # P2WPKH instead
+ pubkeyhash = hash160(hex_str_to_bytes(pubkey))
+ pkscript = CScript([OP_0, pubkeyhash])
+ else:
+ # 1-of-1 multisig
+ witness_program = CScript([OP_1, hex_str_to_bytes(pubkey), OP_1, OP_CHECKMULTISIG])
+ scripthash = sha256(witness_program)
+ pkscript = CScript([OP_0, scripthash])
+ return bytes_to_hex_str(pkscript)
+
+# Return a transaction (in hex) that spends the given utxo to a segwit output,
+# optionally wrapping the segwit output using P2SH.
+def create_witnessprogram(use_p2wsh, utxo, pubkey, encode_p2sh, amount):
+ pkscript = hex_str_to_bytes(witness_script(use_p2wsh, pubkey))
+ if (encode_p2sh):
+ p2sh_hash = hash160(pkscript)
+ pkscript = CScript([OP_HASH160, p2sh_hash, OP_EQUAL])
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), b""))
+ tx.vout.append(CTxOut(int(amount*COIN), pkscript))
+ return ToHex(tx)
+
+# Create a transaction spending a given utxo to a segwit output corresponding
+# to the given pubkey: use_p2wsh determines whether to use P2WPKH or P2WSH;
+# encode_p2sh determines whether to wrap in P2SH.
+# sign=True will have the given node sign the transaction.
+# insert_redeem_script will be added to the scriptSig, if given.
+def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""):
+ tx_to_witness = create_witnessprogram(use_p2wsh, utxo, pubkey, encode_p2sh, amount)
+ if (sign):
+ signed = node.signrawtransaction(tx_to_witness)
+ assert("errors" not in signed or len(["errors"]) == 0)
+ return node.sendrawtransaction(signed["hex"])
+ else:
+ if (insert_redeem_script):
+ tx = FromHex(CTransaction(), tx_to_witness)
+ tx.vin[0].scriptSig += CScript([hex_str_to_bytes(insert_redeem_script)])
+ tx_to_witness = ToHex(tx)
+
+ return node.sendrawtransaction(tx_to_witness)
+
+def getutxo(txid):
+ utxo = {}
+ utxo["vout"] = 0
+ utxo["txid"] = txid
+ return utxo
+
+def find_unspent(node, min_value):
+ for utxo in node.listunspent():
+ if utxo['amount'] >= min_value:
+ return utxo
+
+class SegWitTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+ self.extra_args = [["-walletprematurewitness", "-rpcserialversion=0"],
+ ["-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1"],
+ ["-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]]
+
+ def setup_network(self):
+ super().setup_network()
+ connect_nodes(self.nodes[0], 2)
+ self.sync_all()
+
+ def success_mine(self, node, txid, sign, redeem_script=""):
+ send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
+ block = node.generate(1)
+ assert_equal(len(node.getblock(block[0])["tx"]), 2)
+ sync_blocks(self.nodes)
+
+ def skip_mine(self, node, txid, sign, redeem_script=""):
+ send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
+ block = node.generate(1)
+ assert_equal(len(node.getblock(block[0])["tx"]), 1)
+ sync_blocks(self.nodes)
+
+ def fail_accept(self, node, error_msg, txid, sign, redeem_script=""):
+ assert_raises_jsonrpc(-26, error_msg, send_to_witness, 1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
+
+ def fail_mine(self, node, txid, sign, redeem_script=""):
+ send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
+ assert_raises_jsonrpc(-1, "CreateNewBlock: TestBlockValidity failed", node.generate, 1)
+ sync_blocks(self.nodes)
+
+ def run_test(self):
+ self.nodes[0].generate(161) #block 161
+
+ self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
+ txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+ tmpl = self.nodes[0].getblocktemplate({})
+ assert(tmpl['sizelimit'] == 1000000)
+ assert('weightlimit' not in tmpl)
+ assert(tmpl['sigoplimit'] == 20000)
+ assert(tmpl['transactions'][0]['hash'] == txid)
+ assert(tmpl['transactions'][0]['sigops'] == 2)
+ tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']})
+ assert(tmpl['sizelimit'] == 1000000)
+ assert('weightlimit' not in tmpl)
+ assert(tmpl['sigoplimit'] == 20000)
+ assert(tmpl['transactions'][0]['hash'] == txid)
+ assert(tmpl['transactions'][0]['sigops'] == 2)
+ self.nodes[0].generate(1) #block 162
+
+ balance_presetup = self.nodes[0].getbalance()
+ self.pubkey = []
+ p2sh_ids = [] # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh
+ wit_ids = [] # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness
+ for i in range(3):
+ newaddress = self.nodes[i].getnewaddress()
+ self.pubkey.append(self.nodes[i].validateaddress(newaddress)["pubkey"])
+ multiaddress = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]])
+ self.nodes[i].addwitnessaddress(newaddress)
+ self.nodes[i].addwitnessaddress(multiaddress)
+ p2sh_ids.append([])
+ wit_ids.append([])
+ for v in range(2):
+ p2sh_ids[i].append([])
+ wit_ids[i].append([])
+
+ for i in range(5):
+ for n in range(3):
+ for v in range(2):
+ wit_ids[n][v].append(send_to_witness(v, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[n], False, Decimal("49.999")))
+ p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[n], True, Decimal("49.999")))
+
+ self.nodes[0].generate(1) #block 163
+ sync_blocks(self.nodes)
+
+ # Make sure all nodes recognize the transactions as theirs
+ assert_equal(self.nodes[0].getbalance(), balance_presetup - 60*50 + 20*Decimal("49.999") + 50)
+ assert_equal(self.nodes[1].getbalance(), 20*Decimal("49.999"))
+ assert_equal(self.nodes[2].getbalance(), 20*Decimal("49.999"))
+
+ self.nodes[0].generate(260) #block 423
+ sync_blocks(self.nodes)
+
+ self.log.info("Verify default node can't accept any witness format txs before fork")
+ # unsigned, no scriptsig
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V0][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V1][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False)
+ # unsigned with redeem script
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False, witness_script(False, self.pubkey[0]))
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0]))
+ # signed
+ self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V0][0], True)
+ self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V1][0], True)
+ self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V0][0], True)
+ self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V1][0], True)
+
+ self.log.info("Verify witness txs are skipped for mining before the fork")
+ self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) #block 424
+ self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) #block 425
+ self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) #block 426
+ self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True) #block 427
+
+ # TODO: An old node would see these txs without witnesses and be able to mine them
+
+ self.log.info("Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork")
+ self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][1], False) #block 428
+ self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][1], False) #block 429
+
+ self.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid")
+ self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V0][1], False)
+ self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V1][1], False)
+
+ self.log.info("Verify unsigned p2sh witness txs with a redeem script in versionbits-settings blocks are valid before the fork")
+ self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False, witness_script(False, self.pubkey[2])) #block 430
+ self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False, witness_script(True, self.pubkey[2])) #block 431
+
+ self.log.info("Verify previous witness txs skipped for mining can now be mined")
+ assert_equal(len(self.nodes[2].getrawmempool()), 4)
+ block = self.nodes[2].generate(1) #block 432 (first block with new rules; 432 = 144 * 3)
+ sync_blocks(self.nodes)
+ assert_equal(len(self.nodes[2].getrawmempool()), 0)
+ segwit_tx_list = self.nodes[2].getblock(block[0])["tx"]
+ assert_equal(len(segwit_tx_list), 5)
+
+ self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag")
+ assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False))
+ assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False))
+ for i in range(len(segwit_tx_list)):
+ tx = FromHex(CTransaction(), self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
+ assert(self.nodes[2].getrawtransaction(segwit_tx_list[i]) != self.nodes[0].getrawtransaction(segwit_tx_list[i]))
+ assert(self.nodes[1].getrawtransaction(segwit_tx_list[i], 0) == self.nodes[2].getrawtransaction(segwit_tx_list[i]))
+ assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) != self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
+ assert(self.nodes[1].getrawtransaction(segwit_tx_list[i]) == self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
+ assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) == bytes_to_hex_str(tx.serialize_without_witness()))
+
+ self.log.info("Verify witness txs without witness data are invalid after the fork")
+ self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False)
+ self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][2], False)
+ self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][2], False, witness_script(False, self.pubkey[2]))
+ self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][2], False, witness_script(True, self.pubkey[2]))
+
+ self.log.info("Verify default node can now use witness txs")
+ self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) #block 432
+ self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) #block 433
+ self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) #block 434
+ self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) #block 435
+
+ self.log.info("Verify sigops are counted in GBT with BIP141 rules after the fork")
+ txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+ tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']})
+ assert(tmpl['sizelimit'] >= 3999577) # actual maximum size is lower due to minimum mandatory non-witness data
+ assert(tmpl['weightlimit'] == 4000000)
+ assert(tmpl['sigoplimit'] == 80000)
+ assert(tmpl['transactions'][0]['txid'] == txid)
+ assert(tmpl['transactions'][0]['sigops'] == 8)
+
+ self.nodes[0].generate(1) # Mine a block to clear the gbt cache
+
+ self.log.info("Non-segwit miners are able to use GBT response after activation.")
+ # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) ->
+ # tx2 (segwit input, paying to a non-segwit output) ->
+ # tx3 (non-segwit input, paying to a non-segwit output).
+ # tx1 is allowed to appear in the block, but no others.
+ txid1 = send_to_witness(1, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.996"))
+ hex_tx = self.nodes[0].gettransaction(txid)['hex']
+ tx = FromHex(CTransaction(), hex_tx)
+ assert(tx.wit.is_null()) # This should not be a segwit input
+ assert(txid1 in self.nodes[0].getrawmempool())
+
+ # Now create tx2, which will spend from txid1.
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b''))
+ tx.vout.append(CTxOut(int(49.99*COIN), CScript([OP_TRUE])))
+ tx2_hex = self.nodes[0].signrawtransaction(ToHex(tx))['hex']
+ txid2 = self.nodes[0].sendrawtransaction(tx2_hex)
+ tx = FromHex(CTransaction(), tx2_hex)
+ assert(not tx.wit.is_null())
+
+ # Now create tx3, which will spend from txid2
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b""))
+ tx.vout.append(CTxOut(int(49.95*COIN), CScript([OP_TRUE]))) # Huge fee
+ tx.calc_sha256()
+ txid3 = self.nodes[0].sendrawtransaction(ToHex(tx))
+ assert(tx.wit.is_null())
+ assert(txid3 in self.nodes[0].getrawmempool())
+
+ # Now try calling getblocktemplate() without segwit support.
+ template = self.nodes[0].getblocktemplate()
+
+ # Check that tx1 is the only transaction of the 3 in the template.
+ template_txids = [ t['txid'] for t in template['transactions'] ]
+ assert(txid2 not in template_txids and txid3 not in template_txids)
+ assert(txid1 in template_txids)
+
+ # Check that running with segwit support results in all 3 being included.
+ template = self.nodes[0].getblocktemplate({"rules": ["segwit"]})
+ template_txids = [ t['txid'] for t in template['transactions'] ]
+ assert(txid1 in template_txids)
+ assert(txid2 in template_txids)
+ assert(txid3 in template_txids)
+
+ # Mine a block to clear the gbt cache again.
+ self.nodes[0].generate(1)
+
+ self.log.info("Verify behaviour of importaddress, addwitnessaddress and listunspent")
+
+ # Some public keys to be used later
+ pubkeys = [
+ "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242", # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb
+ "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF", # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97
+ "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E", # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV
+ "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538", # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd
+ "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228", # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66
+ "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC", # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K
+ "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84", # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ
+ ]
+
+ # Import a compressed key and an uncompressed key, generate some multisig addresses
+ self.nodes[0].importprivkey("92e6XLo5jVAVwrQKPNTs93oQco8f8sDNBcpv73Dsrs397fQtFQn")
+ uncompressed_spendable_address = ["mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu"]
+ self.nodes[0].importprivkey("cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR")
+ compressed_spendable_address = ["mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe"]
+ assert ((self.nodes[0].validateaddress(uncompressed_spendable_address[0])['iscompressed'] == False))
+ assert ((self.nodes[0].validateaddress(compressed_spendable_address[0])['iscompressed'] == True))
+
+ self.nodes[0].importpubkey(pubkeys[0])
+ compressed_solvable_address = [key_to_p2pkh(pubkeys[0])]
+ self.nodes[0].importpubkey(pubkeys[1])
+ compressed_solvable_address.append(key_to_p2pkh(pubkeys[1]))
+ self.nodes[0].importpubkey(pubkeys[2])
+ uncompressed_solvable_address = [key_to_p2pkh(pubkeys[2])]
+
+ spendable_anytime = [] # These outputs should be seen anytime after importprivkey and addmultisigaddress
+ spendable_after_importaddress = [] # These outputs should be seen after importaddress
+ solvable_after_importaddress = [] # These outputs should be seen after importaddress but not spendable
+ unsolvable_after_importaddress = [] # These outputs should be unsolvable after importaddress
+ solvable_anytime = [] # These outputs should be solvable after importpubkey
+ unseen_anytime = [] # These outputs should never be seen
+
+ uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]]))
+ uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]]))
+ compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]]))
+ uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], uncompressed_solvable_address[0]]))
+ compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]]))
+ compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], compressed_solvable_address[1]]))
+ unknown_address = ["mtKKyoHabkk6e4ppT7NaM7THqPUt7AzPrT", "2NDP3jLWAFT8NDAiUa9qiE6oBt2awmMq7Dx"]
+
+ # Test multisig_without_privkey
+ # We have 2 public keys without private keys, use addmultisigaddress to add to wallet.
+ # Money sent to P2SH of multisig of this should only be seen after importaddress with the BASE58 P2SH address.
+
+ multisig_without_privkey_address = self.nodes[0].addmultisigaddress(2, [pubkeys[3], pubkeys[4]])
+ script = CScript([OP_2, hex_str_to_bytes(pubkeys[3]), hex_str_to_bytes(pubkeys[4]), OP_2, OP_CHECKMULTISIG])
+ solvable_after_importaddress.append(CScript([OP_HASH160, hash160(script), OP_EQUAL]))
+
+ for i in compressed_spendable_address:
+ v = self.nodes[0].validateaddress(i)
+ if (v['isscript']):
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ # bare and p2sh multisig with compressed keys should always be spendable
+ spendable_anytime.extend([bare, p2sh])
+ # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after direct importaddress
+ spendable_after_importaddress.extend([p2wsh, p2sh_p2wsh])
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # normal P2PKH and P2PK with compressed keys should always be spendable
+ spendable_anytime.extend([p2pkh, p2pk])
+ # P2SH_P2PK, P2SH_P2PKH, and witness with compressed keys are spendable after direct importaddress
+ spendable_after_importaddress.extend([p2wpkh, p2sh_p2wpkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
+
+ for i in uncompressed_spendable_address:
+ v = self.nodes[0].validateaddress(i)
+ if (v['isscript']):
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ # bare and p2sh multisig with uncompressed keys should always be spendable
+ spendable_anytime.extend([bare, p2sh])
+ # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
+ unseen_anytime.extend([p2wsh, p2sh_p2wsh])
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # normal P2PKH and P2PK with uncompressed keys should always be spendable
+ spendable_anytime.extend([p2pkh, p2pk])
+ # P2SH_P2PK and P2SH_P2PKH are spendable after direct importaddress
+ spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
+ # witness with uncompressed keys are never seen
+ unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
+
+ for i in compressed_solvable_address:
+ v = self.nodes[0].validateaddress(i)
+ if (v['isscript']):
+ # Multisig without private is not seen after addmultisigaddress, but seen after importaddress
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ solvable_after_importaddress.extend([bare, p2sh, p2wsh, p2sh_p2wsh])
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # normal P2PKH and P2PK with compressed keys should always be seen
+ solvable_anytime.extend([p2pkh, p2pk])
+ # P2SH_P2PK, P2SH_P2PKH, and witness with compressed keys are seen after direct importaddress
+ solvable_after_importaddress.extend([p2wpkh, p2sh_p2wpkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
+
+ for i in uncompressed_solvable_address:
+ v = self.nodes[0].validateaddress(i)
+ if (v['isscript']):
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ # Base uncompressed multisig without private is not seen after addmultisigaddress, but seen after importaddress
+ solvable_after_importaddress.extend([bare, p2sh])
+ # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
+ unseen_anytime.extend([p2wsh, p2sh_p2wsh])
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # normal P2PKH and P2PK with uncompressed keys should always be seen
+ solvable_anytime.extend([p2pkh, p2pk])
+ # P2SH_P2PK, P2SH_P2PKH with uncompressed keys are seen after direct importaddress
+ solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
+ # witness with uncompressed keys are never seen
+ unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
+
+ op1 = CScript([OP_1])
+ op0 = CScript([OP_0])
+ # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V
+ unsolvable_address = ["mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V", "2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe", script_to_p2sh(op1), script_to_p2sh(op0)]
+ unsolvable_address_key = hex_str_to_bytes("02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D")
+ unsolvablep2pkh = CScript([OP_DUP, OP_HASH160, hash160(unsolvable_address_key), OP_EQUALVERIFY, OP_CHECKSIG])
+ unsolvablep2wshp2pkh = CScript([OP_0, sha256(unsolvablep2pkh)])
+ p2shop0 = CScript([OP_HASH160, hash160(op0), OP_EQUAL])
+ p2wshop1 = CScript([OP_0, sha256(op1)])
+ unsolvable_after_importaddress.append(unsolvablep2pkh)
+ unsolvable_after_importaddress.append(unsolvablep2wshp2pkh)
+ unsolvable_after_importaddress.append(op1) # OP_1 will be imported as script
+ unsolvable_after_importaddress.append(p2wshop1)
+ unseen_anytime.append(op0) # OP_0 will be imported as P2SH address with no script provided
+ unsolvable_after_importaddress.append(p2shop0)
+
+ spendable_txid = []
+ solvable_txid = []
+ spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime, 2))
+ solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime, 1))
+ self.mine_and_test_listunspent(spendable_after_importaddress + solvable_after_importaddress + unseen_anytime + unsolvable_after_importaddress, 0)
+
+ importlist = []
+ for i in compressed_spendable_address + uncompressed_spendable_address + compressed_solvable_address + uncompressed_solvable_address:
+ v = self.nodes[0].validateaddress(i)
+ if (v['isscript']):
+ bare = hex_str_to_bytes(v['hex'])
+ importlist.append(bytes_to_hex_str(bare))
+ importlist.append(bytes_to_hex_str(CScript([OP_0, sha256(bare)])))
+ else:
+ pubkey = hex_str_to_bytes(v['pubkey'])
+ p2pk = CScript([pubkey, OP_CHECKSIG])
+ p2pkh = CScript([OP_DUP, OP_HASH160, hash160(pubkey), OP_EQUALVERIFY, OP_CHECKSIG])
+ importlist.append(bytes_to_hex_str(p2pk))
+ importlist.append(bytes_to_hex_str(p2pkh))
+ importlist.append(bytes_to_hex_str(CScript([OP_0, hash160(pubkey)])))
+ importlist.append(bytes_to_hex_str(CScript([OP_0, sha256(p2pk)])))
+ importlist.append(bytes_to_hex_str(CScript([OP_0, sha256(p2pkh)])))
+
+ importlist.append(bytes_to_hex_str(unsolvablep2pkh))
+ importlist.append(bytes_to_hex_str(unsolvablep2wshp2pkh))
+ importlist.append(bytes_to_hex_str(op1))
+ importlist.append(bytes_to_hex_str(p2wshop1))
+
+ for i in importlist:
+ # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC
+ # exceptions and continue.
+ try:
+ self.nodes[0].importaddress(i,"",False,True)
+ except JSONRPCException as exp:
+ assert_equal(exp.error["message"], "The wallet already contains the private key for this address or script")
+ assert_equal(exp.error["code"], -4)
+
+ self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only
+ self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey
+
+ spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))
+ solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))
+ self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
+ self.mine_and_test_listunspent(unseen_anytime, 0)
+
+ # addwitnessaddress should refuse to return a witness address if an uncompressed key is used or the address is
+ # not in the wallet
+ # note that no witness address should be returned by unsolvable addresses
+ # the multisig_without_privkey_address will fail because its keys were not added with importpubkey
+ for i in uncompressed_spendable_address + uncompressed_solvable_address + unknown_address + unsolvable_address + [multisig_without_privkey_address]:
+ assert_raises_jsonrpc(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i)
+
+ for i in compressed_spendable_address + compressed_solvable_address:
+ witaddress = self.nodes[0].addwitnessaddress(i)
+ # addwitnessaddress should return the same address if it is a known P2SH-witness address
+ assert_equal(witaddress, self.nodes[0].addwitnessaddress(witaddress))
+
+ spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))
+ solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))
+ self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
+ self.mine_and_test_listunspent(unseen_anytime, 0)
+
+ # Repeat some tests. This time we don't add witness scripts with importaddress
+ # Import a compressed key and an uncompressed key, generate some multisig addresses
+ self.nodes[0].importprivkey("927pw6RW8ZekycnXqBQ2JS5nPyo1yRfGNN8oq74HeddWSpafDJH")
+ uncompressed_spendable_address = ["mguN2vNSCEUh6rJaXoAVwY3YZwZvEmf5xi"]
+ self.nodes[0].importprivkey("cMcrXaaUC48ZKpcyydfFo8PxHAjpsYLhdsp6nmtB3E2ER9UUHWnw")
+ compressed_spendable_address = ["n1UNmpmbVUJ9ytXYXiurmGPQ3TRrXqPWKL"]
+
+ self.nodes[0].importpubkey(pubkeys[5])
+ compressed_solvable_address = [key_to_p2pkh(pubkeys[5])]
+ self.nodes[0].importpubkey(pubkeys[6])
+ uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])]
+
+ spendable_after_addwitnessaddress = [] # These outputs should be seen after importaddress
+ solvable_after_addwitnessaddress=[] # These outputs should be seen after importaddress but not spendable
+ unseen_anytime = [] # These outputs should never be seen
+
+ uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]]))
+ uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]]))
+ compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]]))
+ uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], uncompressed_solvable_address[0]]))
+ compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]]))
+
+ premature_witaddress = []
+
+ for i in compressed_spendable_address:
+ v = self.nodes[0].validateaddress(i)
+ if (v['isscript']):
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after addwitnessaddress
+ spendable_after_addwitnessaddress.extend([p2wsh, p2sh_p2wsh])
+ premature_witaddress.append(script_to_p2sh(p2wsh))
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # P2WPKH, P2SH_P2WPKH are spendable after addwitnessaddress
+ spendable_after_addwitnessaddress.extend([p2wpkh, p2sh_p2wpkh])
+ premature_witaddress.append(script_to_p2sh(p2wpkh))
+
+ for i in uncompressed_spendable_address + uncompressed_solvable_address:
+ v = self.nodes[0].validateaddress(i)
+ if (v['isscript']):
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
+ unseen_anytime.extend([p2wsh, p2sh_p2wsh])
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # P2WPKH, P2SH_P2WPKH with uncompressed keys are never seen
+ unseen_anytime.extend([p2wpkh, p2sh_p2wpkh])
+
+ for i in compressed_solvable_address:
+ v = self.nodes[0].validateaddress(i)
+ if (v['isscript']):
+ # P2WSH multisig without private key are seen after addwitnessaddress
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ solvable_after_addwitnessaddress.extend([p2wsh, p2sh_p2wsh])
+ premature_witaddress.append(script_to_p2sh(p2wsh))
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # P2SH_P2PK, P2SH_P2PKH with compressed keys are seen after addwitnessaddress
+ solvable_after_addwitnessaddress.extend([p2wpkh, p2sh_p2wpkh])
+ premature_witaddress.append(script_to_p2sh(p2wpkh))
+
+ self.mine_and_test_listunspent(spendable_after_addwitnessaddress + solvable_after_addwitnessaddress + unseen_anytime, 0)
+
+ # addwitnessaddress should refuse to return a witness address if an uncompressed key is used
+ # note that a multisig address returned by addmultisigaddress is not solvable until it is added with importaddress
+ # premature_witaddress are not accepted until the script is added with addwitnessaddress first
+ for i in uncompressed_spendable_address + uncompressed_solvable_address + premature_witaddress + [compressed_solvable_address[1]]:
+ # This will raise an exception
+ assert_raises_jsonrpc(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i)
+
+ # after importaddress it should pass addwitnessaddress
+ v = self.nodes[0].validateaddress(compressed_solvable_address[1])
+ self.nodes[0].importaddress(v['hex'],"",False,True)
+ for i in compressed_spendable_address + compressed_solvable_address + premature_witaddress:
+ witaddress = self.nodes[0].addwitnessaddress(i)
+ assert_equal(witaddress, self.nodes[0].addwitnessaddress(witaddress))
+
+ spendable_txid.append(self.mine_and_test_listunspent(spendable_after_addwitnessaddress, 2))
+ solvable_txid.append(self.mine_and_test_listunspent(solvable_after_addwitnessaddress, 1))
+ self.mine_and_test_listunspent(unseen_anytime, 0)
+
+ # Check that spendable outputs are really spendable
+ self.create_and_mine_tx_from_txids(spendable_txid)
+
+ # import all the private keys so solvable addresses become spendable
+ self.nodes[0].importprivkey("cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb")
+ self.nodes[0].importprivkey("cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97")
+ self.nodes[0].importprivkey("91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV")
+ self.nodes[0].importprivkey("cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd")
+ self.nodes[0].importprivkey("cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66")
+ self.nodes[0].importprivkey("cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K")
+ self.create_and_mine_tx_from_txids(solvable_txid)
+
+ def mine_and_test_listunspent(self, script_list, ismine):
+ utxo = find_unspent(self.nodes[0], 50)
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(int('0x'+utxo['txid'],0), utxo['vout'])))
+ for i in script_list:
+ tx.vout.append(CTxOut(10000000, i))
+ tx.rehash()
+ signresults = self.nodes[0].signrawtransaction(bytes_to_hex_str(tx.serialize_without_witness()))['hex']
+ txid = self.nodes[0].sendrawtransaction(signresults, True)
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+ watchcount = 0
+ spendcount = 0
+ for i in self.nodes[0].listunspent():
+ if (i['txid'] == txid):
+ watchcount += 1
+ if (i['spendable'] == True):
+ spendcount += 1
+ if (ismine == 2):
+ assert_equal(spendcount, len(script_list))
+ elif (ismine == 1):
+ assert_equal(watchcount, len(script_list))
+ assert_equal(spendcount, 0)
+ else:
+ assert_equal(watchcount, 0)
+ return txid
+
+ def p2sh_address_to_script(self,v):
+ bare = CScript(hex_str_to_bytes(v['hex']))
+ p2sh = CScript(hex_str_to_bytes(v['scriptPubKey']))
+ p2wsh = CScript([OP_0, sha256(bare)])
+ p2sh_p2wsh = CScript([OP_HASH160, hash160(p2wsh), OP_EQUAL])
+ return([bare, p2sh, p2wsh, p2sh_p2wsh])
+
+ def p2pkh_address_to_script(self,v):
+ pubkey = hex_str_to_bytes(v['pubkey'])
+ p2wpkh = CScript([OP_0, hash160(pubkey)])
+ p2sh_p2wpkh = CScript([OP_HASH160, hash160(p2wpkh), OP_EQUAL])
+ p2pk = CScript([pubkey, OP_CHECKSIG])
+ p2pkh = CScript(hex_str_to_bytes(v['scriptPubKey']))
+ p2sh_p2pk = CScript([OP_HASH160, hash160(p2pk), OP_EQUAL])
+ p2sh_p2pkh = CScript([OP_HASH160, hash160(p2pkh), OP_EQUAL])
+ p2wsh_p2pk = CScript([OP_0, sha256(p2pk)])
+ p2wsh_p2pkh = CScript([OP_0, sha256(p2pkh)])
+ p2sh_p2wsh_p2pk = CScript([OP_HASH160, hash160(p2wsh_p2pk), OP_EQUAL])
+ p2sh_p2wsh_p2pkh = CScript([OP_HASH160, hash160(p2wsh_p2pkh), OP_EQUAL])
+ return [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh]
+
+ def create_and_mine_tx_from_txids(self, txids, success = True):
+ tx = CTransaction()
+ for i in txids:
+ txtmp = CTransaction()
+ txraw = self.nodes[0].getrawtransaction(i)
+ f = BytesIO(hex_str_to_bytes(txraw))
+ txtmp.deserialize(f)
+ for j in range(len(txtmp.vout)):
+ tx.vin.append(CTxIn(COutPoint(int('0x'+i,0), j)))
+ tx.vout.append(CTxOut(0, CScript()))
+ tx.rehash()
+ signresults = self.nodes[0].signrawtransaction(bytes_to_hex_str(tx.serialize_without_witness()))['hex']
+ self.nodes[0].sendrawtransaction(signresults, True)
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+
+
+if __name__ == '__main__':
+ SegWitTest().main()
diff --git a/qa/rpc-tests/sendheaders.py b/test/functional/sendheaders.py
index c3f3180b6b..44c357c6db 100755
--- a/qa/rpc-tests/sendheaders.py
+++ b/test/functional/sendheaders.py
@@ -2,14 +2,7 @@
# Copyright (c) 2014-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 test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.blocktools import create_block, create_coinbase
-
-'''
-SendHeadersTest -- test behavior of headers messages to announce blocks.
+"""Test behavior of headers messages to announce blocks.
Setup:
@@ -78,31 +71,27 @@ d. Announce 49 headers that don't connect.
Expect: getheaders message each time.
e. Announce one more that doesn't connect.
Expect: disconnect.
-'''
+"""
-class BaseNode(NodeConnCB):
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+from test_framework.blocktools import create_block, create_coinbase
+
+
+direct_fetch_response_time = 0.05
+
+class TestNode(NodeConnCB):
def __init__(self):
- NodeConnCB.__init__(self)
- self.connection = None
- self.last_inv = None
- self.last_headers = None
- self.last_block = None
- self.ping_counter = 1
- self.last_pong = msg_pong(0)
- self.last_getdata = None
- self.sleep_time = 0.05
+ super().__init__()
self.block_announced = False
- self.last_getheaders = None
- self.disconnected = False
+ self.last_blockhash_announced = None
def clear_last_announcement(self):
with mininode_lock:
self.block_announced = False
- self.last_inv = None
- self.last_headers = None
-
- def add_connection(self, conn):
- self.connection = conn
+ self.last_message.pop("inv", None)
+ self.last_message.pop("headers", None)
# Request data for a list of block hashes
def get_data(self, block_hashes):
@@ -122,33 +111,18 @@ class BaseNode(NodeConnCB):
msg.inv = [CInv(2, blockhash)]
self.connection.send_message(msg)
- # Wrapper for the NodeConn's send_message function
- def send_message(self, message):
- self.connection.send_message(message)
-
def on_inv(self, conn, message):
- self.last_inv = message
self.block_announced = True
+ self.last_blockhash_announced = message.inv[-1].hash
def on_headers(self, conn, message):
- self.last_headers = message
- self.block_announced = True
+ if len(message.headers):
+ self.block_announced = True
+ message.headers[-1].calc_sha256()
+ self.last_blockhash_announced = message.headers[-1].sha256
def on_block(self, conn, message):
- self.last_block = message.block
- self.last_block.calc_sha256()
-
- def on_getdata(self, conn, message):
- self.last_getdata = message
-
- def on_pong(self, conn, message):
- self.last_pong = message
-
- def on_getheaders(self, conn, message):
- self.last_getheaders = message
-
- def on_close(self, conn):
- self.disconnected = True
+ self.last_message["block"].calc_sha256()
# Test whether the last announcement we received had the
# right header or the right inv
@@ -157,66 +131,39 @@ class BaseNode(NodeConnCB):
expect_headers = headers if headers != None else []
expect_inv = inv if inv != None else []
test_function = lambda: self.block_announced
- self.sync(test_function)
+ assert(wait_until(test_function, timeout=60))
with mininode_lock:
self.block_announced = False
success = True
compare_inv = []
- if self.last_inv != None:
- compare_inv = [x.hash for x in self.last_inv.inv]
+ if "inv" in self.last_message:
+ compare_inv = [x.hash for x in self.last_message["inv"].inv]
if compare_inv != expect_inv:
success = False
hash_headers = []
- if self.last_headers != None:
+ if "headers" in self.last_message:
# treat headers as a list of block hashes
- hash_headers = [ x.sha256 for x in self.last_headers.headers ]
+ hash_headers = [ x.sha256 for x in self.last_message["headers"].headers ]
if hash_headers != expect_headers:
success = False
- self.last_inv = None
- self.last_headers = None
+ self.last_message.pop("inv", None)
+ self.last_message.pop("headers", None)
return success
- # Syncing helpers
- def sync(self, test_function, timeout=60):
- while timeout > 0:
- with mininode_lock:
- if test_function():
- return
- time.sleep(self.sleep_time)
- timeout -= self.sleep_time
- raise AssertionError("Sync failed to complete")
-
- def sync_with_ping(self, timeout=60):
- self.send_message(msg_ping(nonce=self.ping_counter))
- test_function = lambda: self.last_pong.nonce == self.ping_counter
- self.sync(test_function, timeout)
- self.ping_counter += 1
- return
-
- def wait_for_block(self, blockhash, timeout=60):
- test_function = lambda: self.last_block != None and self.last_block.sha256 == blockhash
- self.sync(test_function, timeout)
- return
-
- def wait_for_getheaders(self, timeout=60):
- test_function = lambda: self.last_getheaders != None
- self.sync(test_function, timeout)
- return
-
def wait_for_getdata(self, hash_list, timeout=60):
if hash_list == []:
return
- test_function = lambda: self.last_getdata != None and [x.hash for x in self.last_getdata.inv] == hash_list
- self.sync(test_function, timeout)
+ test_function = lambda: "getdata" in self.last_message and [x.hash for x in self.last_message["getdata"].inv] == hash_list
+ assert(wait_until(test_function, timeout=timeout))
return
- def wait_for_disconnect(self, timeout=60):
- test_function = lambda: self.disconnected
- self.sync(test_function, timeout)
+ def wait_for_block_announcement(self, block_hash, timeout=60):
+ test_function = lambda: self.last_blockhash_announced == block_hash
+ assert(wait_until(test_function, timeout=timeout))
return
def send_header_for_blocks(self, new_blocks):
@@ -229,28 +176,12 @@ class BaseNode(NodeConnCB):
getblocks_message.locator.vHave = locator
self.send_message(getblocks_message)
-# InvNode: This peer should only ever receive inv's, because it doesn't ever send a
-# "sendheaders" message.
-class InvNode(BaseNode):
- def __init__(self):
- BaseNode.__init__(self)
-
-# TestNode: This peer is the one we use for most of the testing.
-class TestNode(BaseNode):
- def __init__(self):
- BaseNode.__init__(self)
-
class SendHeadersTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 2
- def setup_network(self):
- self.nodes = []
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [["-debug", "-logtimemicros=1"]]*2)
- connect_nodes(self.nodes[0], 1)
-
# mine count blocks and return the new tip
def mine_blocks(self, count):
# Clear out last block announcement from each p2p listener
@@ -266,7 +197,9 @@ class SendHeadersTest(BitcoinTestFramework):
def mine_reorg(self, length):
self.nodes[0].generate(length) # make sure all invalidated blocks are node0's
sync_blocks(self.nodes, wait=0.1)
- [x.clear_last_announcement() for x in self.p2p_connections]
+ for x in self.p2p_connections:
+ x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))
+ x.clear_last_announcement()
tip_height = self.nodes[1].getblockcount()
hash_to_invalidate = self.nodes[1].getblockhash(tip_height-(length-1))
@@ -277,7 +210,7 @@ class SendHeadersTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connections and start up the network thread.
- inv_node = InvNode()
+ inv_node = TestNode()
test_node = TestNode()
self.p2p_connections = [inv_node, test_node]
@@ -300,7 +233,7 @@ class SendHeadersTest(BitcoinTestFramework):
# PART 1
# 1. Mine a block; expect inv announcements each time
- print("Part 1: headers don't start before sendheaders message...")
+ self.log.info("Part 1: headers don't start before sendheaders message...")
for i in range(4):
old_tip = tip
tip = self.mine_blocks(1)
@@ -310,7 +243,7 @@ class SendHeadersTest(BitcoinTestFramework):
if i == 0:
# first request the block
test_node.get_data([tip])
- test_node.wait_for_block(tip, timeout=5)
+ test_node.wait_for_block(tip)
elif i == 1:
# next try requesting header and block
test_node.get_headers(locator=[old_tip], hashstop=tip)
@@ -325,14 +258,14 @@ class SendHeadersTest(BitcoinTestFramework):
new_block = create_block(tip, create_coinbase(height+1), block_time)
new_block.solve()
test_node.send_header_for_blocks([new_block])
- test_node.wait_for_getdata([new_block.sha256], timeout=5)
+ test_node.wait_for_getdata([new_block.sha256])
test_node.send_message(msg_block(new_block))
test_node.sync_with_ping() # make sure this block is processed
inv_node.clear_last_announcement()
test_node.clear_last_announcement()
- print("Part 1: success!")
- print("Part 2: announce blocks with headers after sendheaders message...")
+ self.log.info("Part 1: success!")
+ self.log.info("Part 2: announce blocks with headers after sendheaders message...")
# PART 2
# 2. Send a sendheaders message and test that headers announcements
# commence and keep working.
@@ -364,19 +297,18 @@ class SendHeadersTest(BitcoinTestFramework):
if j == 0:
# Announce via inv
test_node.send_block_inv(tip)
- test_node.wait_for_getdata([tip], timeout=5)
+ test_node.wait_for_getheaders()
+ # Should have received a getheaders now
+ test_node.send_header_for_blocks(blocks)
# Test that duplicate inv's won't result in duplicate
# getdata requests, or duplicate headers announcements
- inv_node.send_block_inv(tip)
- # Should have received a getheaders as well!
- test_node.send_header_for_blocks(blocks)
- test_node.wait_for_getdata([x.sha256 for x in blocks[0:-1]], timeout=5)
- [ inv_node.send_block_inv(x.sha256) for x in blocks[0:-1] ]
+ [ inv_node.send_block_inv(x.sha256) for x in blocks ]
+ test_node.wait_for_getdata([x.sha256 for x in blocks])
inv_node.sync_with_ping()
else:
# Announce via headers
test_node.send_header_for_blocks(blocks)
- test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5)
+ test_node.wait_for_getdata([x.sha256 for x in blocks])
# Test that duplicate headers won't result in duplicate
# getdata requests (the check is further down)
inv_node.send_header_for_blocks(blocks)
@@ -386,17 +318,17 @@ class SendHeadersTest(BitcoinTestFramework):
inv_node.sync_with_ping()
# This block should not be announced to the inv node (since it also
# broadcast it)
- assert_equal(inv_node.last_inv, None)
- assert_equal(inv_node.last_headers, None)
+ assert "inv" not in inv_node.last_message
+ assert "headers" not in inv_node.last_message
tip = self.mine_blocks(1)
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
assert_equal(test_node.check_last_announcement(headers=[tip]), True)
height += 1
block_time += 1
- print("Part 2: success!")
+ self.log.info("Part 2: success!")
- print("Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer...")
+ self.log.info("Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer...")
# PART 3. Headers announcements can stop after large reorg, and resume after
# getheaders or inv from peer.
@@ -458,9 +390,9 @@ class SendHeadersTest(BitcoinTestFramework):
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
assert_equal(test_node.check_last_announcement(headers=[tip]), True)
- print("Part 3: success!")
+ self.log.info("Part 3: success!")
- print("Part 4: Testing direct fetch behavior...")
+ self.log.info("Part 4: Testing direct fetch behavior...")
tip = self.mine_blocks(1)
height = self.nodes[0].getblockcount() + 1
last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time']
@@ -477,12 +409,12 @@ class SendHeadersTest(BitcoinTestFramework):
inv_node.send_message(msg_block(blocks[-1]))
inv_node.sync_with_ping() # Make sure blocks are processed
- test_node.last_getdata = None
+ test_node.last_message.pop("getdata", None)
test_node.send_header_for_blocks(blocks)
test_node.sync_with_ping()
# should not have received any getdata messages
with mininode_lock:
- assert_equal(test_node.last_getdata, None)
+ assert "getdata" not in test_node.last_message
# This time, direct fetch should work
blocks = []
@@ -495,7 +427,7 @@ class SendHeadersTest(BitcoinTestFramework):
test_node.send_header_for_blocks(blocks)
test_node.sync_with_ping()
- test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=test_node.sleep_time)
+ test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=direct_fetch_response_time)
[ test_node.send_message(msg_block(x)) for x in blocks ]
@@ -516,41 +448,41 @@ class SendHeadersTest(BitcoinTestFramework):
# Announcing one block on fork should not trigger direct fetch
# (less work than tip)
- test_node.last_getdata = None
+ test_node.last_message.pop("getdata", None)
test_node.send_header_for_blocks(blocks[0:1])
test_node.sync_with_ping()
with mininode_lock:
- assert_equal(test_node.last_getdata, None)
+ assert "getdata" not in test_node.last_message
# Announcing one more block on fork should trigger direct fetch for
# both blocks (same work as tip)
test_node.send_header_for_blocks(blocks[1:2])
test_node.sync_with_ping()
- test_node.wait_for_getdata([x.sha256 for x in blocks[0:2]], timeout=test_node.sleep_time)
+ test_node.wait_for_getdata([x.sha256 for x in blocks[0:2]], timeout=direct_fetch_response_time)
# Announcing 16 more headers should trigger direct fetch for 14 more
# blocks
test_node.send_header_for_blocks(blocks[2:18])
test_node.sync_with_ping()
- test_node.wait_for_getdata([x.sha256 for x in blocks[2:16]], timeout=test_node.sleep_time)
+ test_node.wait_for_getdata([x.sha256 for x in blocks[2:16]], timeout=direct_fetch_response_time)
# Announcing 1 more header should not trigger any response
- test_node.last_getdata = None
+ test_node.last_message.pop("getdata", None)
test_node.send_header_for_blocks(blocks[18:19])
test_node.sync_with_ping()
with mininode_lock:
- assert_equal(test_node.last_getdata, None)
+ assert "getdata" not in test_node.last_message
- print("Part 4: success!")
+ self.log.info("Part 4: success!")
# Now deliver all those blocks we announced.
[ test_node.send_message(msg_block(x)) for x in blocks ]
- print("Part 5: Testing handling of unconnecting headers")
+ self.log.info("Part 5: Testing handling of unconnecting headers")
# First we test that receipt of an unconnecting header doesn't prevent
# chain sync.
for i in range(10):
- test_node.last_getdata = None
+ test_node.last_message.pop("getdata", None)
blocks = []
# Create two more blocks.
for j in range(2):
@@ -561,9 +493,9 @@ class SendHeadersTest(BitcoinTestFramework):
height += 1
# Send the header of the second block -> this won't connect.
with mininode_lock:
- test_node.last_getheaders = None
+ test_node.last_message.pop("getheaders", None)
test_node.send_header_for_blocks([blocks[1]])
- test_node.wait_for_getheaders(timeout=1)
+ test_node.wait_for_getheaders()
test_node.send_header_for_blocks(blocks)
test_node.wait_for_getdata([x.sha256 for x in blocks])
[ test_node.send_message(msg_block(x)) for x in blocks ]
@@ -584,9 +516,9 @@ class SendHeadersTest(BitcoinTestFramework):
for i in range(1, MAX_UNCONNECTING_HEADERS):
# Send a header that doesn't connect, check that we get a getheaders.
with mininode_lock:
- test_node.last_getheaders = None
+ test_node.last_message.pop("getheaders", None)
test_node.send_header_for_blocks([blocks[i]])
- test_node.wait_for_getheaders(timeout=1)
+ test_node.wait_for_getheaders()
# Next header will connect, should re-set our count:
test_node.send_header_for_blocks([blocks[0]])
@@ -599,25 +531,21 @@ class SendHeadersTest(BitcoinTestFramework):
for i in range(5*MAX_UNCONNECTING_HEADERS - 1):
# Send a header that doesn't connect, check that we get a getheaders.
with mininode_lock:
- test_node.last_getheaders = None
+ test_node.last_message.pop("getheaders", None)
test_node.send_header_for_blocks([blocks[i%len(blocks)]])
- test_node.wait_for_getheaders(timeout=1)
+ test_node.wait_for_getheaders()
# Eventually this stops working.
- with mininode_lock:
- self.last_getheaders = None
test_node.send_header_for_blocks([blocks[-1]])
# Should get disconnected
test_node.wait_for_disconnect()
- with mininode_lock:
- self.last_getheaders = True
- print("Part 5: success!")
+ self.log.info("Part 5: success!")
# Finally, check that the inv node never received a getdata request,
# throughout the test
- assert_equal(inv_node.last_getdata, None)
+ assert "getdata" not in inv_node.last_message
if __name__ == '__main__':
SendHeadersTest().main()
diff --git a/qa/rpc-tests/signmessages.py b/test/functional/signmessages.py
index 31b6f14a26..42f6a9daaf 100755
--- a/qa/rpc-tests/signmessages.py
+++ b/test/functional/signmessages.py
@@ -2,23 +2,17 @@
# Copyright (c) 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.
+"""Test RPC commands for signing and verifying messages."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-
class SignMessagesTest(BitcoinTestFramework):
- """Tests RPC commands for signing and verifying messages."""
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
- def setup_network(self, split=False):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
- self.is_network_split = False
-
def run_test(self):
message = 'This is just a test message'
diff --git a/qa/rpc-tests/signrawtransactions.py b/test/functional/signrawtransactions.py
index c61a280616..fc49c23b9f 100755
--- a/qa/rpc-tests/signrawtransactions.py
+++ b/test/functional/signrawtransactions.py
@@ -2,36 +2,33 @@
# Copyright (c) 2015-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.
+"""Test transaction signing using the signrawtransaction RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class SignRawTransactionsTest(BitcoinTestFramework):
- """Tests transaction signing via RPC command "signrawtransaction"."""
-
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
- def setup_network(self, split=False):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
- self.is_network_split = False
-
def successful_signing_test(self):
- """Creates and signs a valid raw transaction with one input.
+ """Create and sign a valid raw transaction with one input.
Expected results:
1) The transaction has a complete set of signatures
2) No script verification error occurred"""
- privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N']
+ privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N', 'cVKpPfVKSJxKqVpE9awvXNWuLHCa5j5tiE7K6zbUSptFpTEtiFrA']
inputs = [
- # Valid pay-to-pubkey script
+ # Valid pay-to-pubkey scripts
{'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0,
- 'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'}
+ 'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'},
+ {'txid': '83a4f6a6b73660e13ee6cb3c6063fa3759c50c9b7521d0536022961898f4fb02', 'vout': 0,
+ 'scriptPubKey': '76a914669b857c03a5ed269d5d85a1ffac9ed5d663072788ac'},
]
outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1}
@@ -46,8 +43,24 @@ class SignRawTransactionsTest(BitcoinTestFramework):
# 2) No script verification error occurred
assert 'errors' not in rawTxSigned
+ # Check that signrawtransaction doesn't blow up on garbage merge attempts
+ dummyTxInconsistent = self.nodes[0].createrawtransaction([inputs[0]], outputs)
+ rawTxUnsigned = self.nodes[0].signrawtransaction(rawTx + dummyTxInconsistent, inputs)
+
+ assert 'complete' in rawTxUnsigned
+ assert_equal(rawTxUnsigned['complete'], False)
+
+ # Check that signrawtransaction properly merges unsigned and signed txn, even with garbage in the middle
+ rawTxSigned2 = self.nodes[0].signrawtransaction(rawTxUnsigned["hex"] + dummyTxInconsistent + rawTxSigned["hex"], inputs)
+
+ assert 'complete' in rawTxSigned2
+ assert_equal(rawTxSigned2['complete'], True)
+
+ assert 'errors' not in rawTxSigned2
+
+
def script_verification_error_test(self):
- """Creates and signs a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script.
+ """Create and sign a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script.
Expected results:
@@ -78,6 +91,16 @@ class SignRawTransactionsTest(BitcoinTestFramework):
outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1}
rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
+
+ # Make sure decoderawtransaction is at least marginally sane
+ decodedRawTx = self.nodes[0].decoderawtransaction(rawTx)
+ for i, inp in enumerate(inputs):
+ assert_equal(decodedRawTx["vin"][i]["txid"], inp["txid"])
+ assert_equal(decodedRawTx["vin"][i]["vout"], inp["vout"])
+
+ # Make sure decoderawtransaction throws if there is extra data
+ assert_raises(JSONRPCException, self.nodes[0].decoderawtransaction, rawTx + "00")
+
rawTxSigned = self.nodes[0].signrawtransaction(rawTx, scripts, privKeys)
# 3) The transaction has no complete set of signatures
diff --git a/qa/rpc-tests/smartfees.py b/test/functional/smartfees.py
index d76fba4b07..19ffe9e851 100755
--- a/qa/rpc-tests/smartfees.py
+++ b/test/functional/smartfees.py
@@ -2,26 +2,28 @@
# Copyright (c) 2014-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.
+"""Test fee estimation code."""
-#
-# Test fee estimation code
-#
-
-from collections import OrderedDict
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
+from test_framework.script import CScript, OP_1, OP_DROP, OP_2, OP_HASH160, OP_EQUAL, hash160, OP_TRUE
+from test_framework.mininode import CTransaction, CTxIn, CTxOut, COutPoint, ToHex, COIN
# Construct 2 trivial P2SH's and the ScriptSigs that spend them
# So we can create many many transactions without needing to spend
# time signing.
-P2SH_1 = "2MySexEGVzZpRgNQ1JdjdP5bRETznm3roQ2" # P2SH of "OP_1 OP_DROP"
-P2SH_2 = "2NBdpwq8Aoo1EEKEXPNrKvr5xQr3M9UfcZA" # P2SH of "OP_2 OP_DROP"
+redeem_script_1 = CScript([OP_1, OP_DROP])
+redeem_script_2 = CScript([OP_2, OP_DROP])
+P2SH_1 = CScript([OP_HASH160, hash160(redeem_script_1), OP_EQUAL])
+P2SH_2 = CScript([OP_HASH160, hash160(redeem_script_2), OP_EQUAL])
+
# Associated ScriptSig's to spend satisfy P2SH_1 and P2SH_2
-# 4 bytes of OP_TRUE and push 2-byte redeem script of "OP_1 OP_DROP" or "OP_2 OP_DROP"
-SCRIPT_SIG = ["0451025175", "0451025275"]
+SCRIPT_SIG = [CScript([OP_TRUE, redeem_script_1]), CScript([OP_TRUE, redeem_script_2])]
+
+global log
def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee_increment):
- '''
+ """
Create and send a transaction with a random fee.
The transaction pays to a trivial P2SH script, and assumes that its inputs
are of the same form.
@@ -29,79 +31,74 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
and attempts to use the confirmed list first for its inputs.
It adds the newly created outputs to the unconfirmed list.
Returns (raw transaction, fee)
- '''
+ """
# It's best to exponentially distribute our random fees
# because the buckets are exponentially spaced.
# Exponentially distributed from 1-128 * fee_increment
rand_fee = float(fee_increment)*(1.1892**random.randint(0,28))
# Total fee ranges from min_fee to min_fee + 127*fee_increment
fee = min_fee - fee_increment + satoshi_round(rand_fee)
- inputs = []
+ tx = CTransaction()
total_in = Decimal("0.00000000")
while total_in <= (amount + fee) and len(conflist) > 0:
t = conflist.pop(0)
total_in += t["amount"]
- inputs.append({ "txid" : t["txid"], "vout" : t["vout"]} )
+ tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), b""))
if total_in <= amount + fee:
while total_in <= (amount + fee) and len(unconflist) > 0:
t = unconflist.pop(0)
total_in += t["amount"]
- inputs.append({ "txid" : t["txid"], "vout" : t["vout"]} )
+ tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), b""))
if total_in <= amount + fee:
raise RuntimeError("Insufficient funds: need %d, have %d"%(amount+fee, total_in))
- outputs = {}
- outputs = OrderedDict([(P2SH_1, total_in - amount - fee),
- (P2SH_2, amount)])
- rawtx = from_node.createrawtransaction(inputs, outputs)
- # createrawtransaction constructs a transaction that is ready to be signed.
- # These transactions don't need to be signed, but we still have to insert the ScriptSig
- # that will satisfy the ScriptPubKey.
- completetx = rawtx[0:10]
- inputnum = 0
- for inp in inputs:
- completetx += rawtx[10+82*inputnum:82+82*inputnum]
- completetx += SCRIPT_SIG[inp["vout"]]
- completetx += rawtx[84+82*inputnum:92+82*inputnum]
- inputnum += 1
- completetx += rawtx[10+82*inputnum:]
- txid = from_node.sendrawtransaction(completetx, True)
+ tx.vout.append(CTxOut(int((total_in - amount - fee)*COIN), P2SH_1))
+ tx.vout.append(CTxOut(int(amount*COIN), P2SH_2))
+ # These transactions don't need to be signed, but we still have to insert
+ # the ScriptSig that will satisfy the ScriptPubKey.
+ for inp in tx.vin:
+ inp.scriptSig = SCRIPT_SIG[inp.prevout.n]
+ txid = from_node.sendrawtransaction(ToHex(tx), True)
unconflist.append({ "txid" : txid, "vout" : 0 , "amount" : total_in - amount - fee})
unconflist.append({ "txid" : txid, "vout" : 1 , "amount" : amount})
- return (completetx, fee)
+ return (ToHex(tx), fee)
def split_inputs(from_node, txins, txouts, initial_split = False):
- '''
- We need to generate a lot of very small inputs so we can generate a ton of transactions
- and they will have low priority.
+ """
+ We need to generate a lot of inputs so we can generate a ton of transactions.
This function takes an input from txins, and creates and sends a transaction
which splits the value into 2 outputs which are appended to txouts.
- '''
+ Previously this was designed to be small inputs so they wouldn't have
+ a high coin age when the notion of priority still existed.
+ """
prevtxout = txins.pop()
- inputs = []
- inputs.append({ "txid" : prevtxout["txid"], "vout" : prevtxout["vout"] })
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(int(prevtxout["txid"], 16), prevtxout["vout"]), b""))
+
half_change = satoshi_round(prevtxout["amount"]/2)
rem_change = prevtxout["amount"] - half_change - Decimal("0.00001000")
- outputs = OrderedDict([(P2SH_1, half_change), (P2SH_2, rem_change)])
- rawtx = from_node.createrawtransaction(inputs, outputs)
+ tx.vout.append(CTxOut(int(half_change*COIN), P2SH_1))
+ tx.vout.append(CTxOut(int(rem_change*COIN), P2SH_2))
+
# If this is the initial split we actually need to sign the transaction
- # Otherwise we just need to insert the property ScriptSig
+ # Otherwise we just need to insert the proper ScriptSig
if (initial_split) :
- completetx = from_node.signrawtransaction(rawtx)["hex"]
+ completetx = from_node.signrawtransaction(ToHex(tx))["hex"]
else :
- completetx = rawtx[0:82] + SCRIPT_SIG[prevtxout["vout"]] + rawtx[84:]
+ tx.vin[0].scriptSig = SCRIPT_SIG[prevtxout["vout"]]
+ completetx = ToHex(tx)
txid = from_node.sendrawtransaction(completetx, True)
txouts.append({ "txid" : txid, "vout" : 0 , "amount" : half_change})
txouts.append({ "txid" : txid, "vout" : 1 , "amount" : rem_change})
def check_estimates(node, fees_seen, max_invalid, print_estimates = True):
- '''
+ """
This function calls estimatefee and verifies that the estimates
meet certain invariants.
- '''
+ """
all_estimates = [ node.estimatefee(i) for i in range(1,26) ]
if print_estimates:
- print([str(all_estimates[e-1]) for e in [1,2,3,6,15,25]])
+ log.info([str(all_estimates[e-1]) for e in [1,2,3,6,15,25]])
delta = 1.0e-6 # account for rounding error
last_e = max(fees_seen)
for e in [x for x in all_estimates if x >= 0]:
@@ -151,18 +148,18 @@ class EstimateFeeTest(BitcoinTestFramework):
self.setup_clean_chain = False
def setup_network(self):
- '''
+ """
We'll setup the network to have 3 nodes that all mine with different parameters.
- But first we need to use one node to create a lot of small low priority outputs
+ But first we need to use one node to create a lot of outputs
which we will use to generate our transactions.
- '''
+ """
self.nodes = []
# Use node0 to mine blocks for input splitting
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
- "-relaypriority=0", "-whitelist=127.0.0.1"]))
+ "-whitelist=127.0.0.1"]))
- print("This test is time consuming, please be patient")
- print("Splitting inputs to small size so we can generate low priority tx's")
+ self.log.info("This test is time consuming, please be patient")
+ self.log.info("Splitting inputs so we can generate tx's")
self.txouts = []
self.txouts2 = []
# Split a coinbase into two transaction puzzle outputs
@@ -187,28 +184,25 @@ class EstimateFeeTest(BitcoinTestFramework):
while (len(self.nodes[0].getrawmempool()) > 0):
self.nodes[0].generate(1)
reps += 1
- print("Finished splitting")
+ self.log.info("Finished splitting")
# Now we can connect the other nodes, didn't want to connect them earlier
# so the estimates would not be affected by the splitting transactions
- # Node1 mines small blocks but that are bigger than the expected transaction rate,
- # and allows free transactions.
+ # Node1 mines small blocks but that are bigger than the expected transaction rate.
# NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes,
# (17k is room enough for 110 or so transactions)
self.nodes.append(start_node(1, self.options.tmpdir,
- ["-blockprioritysize=1500", "-blockmaxsize=17000",
- "-maxorphantx=1000", "-relaypriority=0", "-debug=estimatefee"]))
+ ["-blockmaxsize=17000", "-maxorphantx=1000"]))
connect_nodes(self.nodes[1], 0)
# Node2 is a stingy miner, that
# produces too small blocks (room for only 55 or so transactions)
- node2args = ["-blockprioritysize=0", "-blockmaxsize=8000", "-maxorphantx=1000", "-relaypriority=0"]
+ node2args = ["-blockmaxsize=8000", "-maxorphantx=1000"]
self.nodes.append(start_node(2, self.options.tmpdir, node2args))
connect_nodes(self.nodes[0], 2)
connect_nodes(self.nodes[2], 1)
- self.is_network_split = False
self.sync_all()
def transact_and_mine(self, numblocks, mining_node):
@@ -225,9 +219,9 @@ class EstimateFeeTest(BitcoinTestFramework):
self.memutxo, Decimal("0.005"), min_fee, min_fee)
tx_kbytes = (len(txhex) // 2) / 1000.0
self.fees_per_kb.append(float(fee)/tx_kbytes)
- sync_mempools(self.nodes[0:3],.1)
+ sync_mempools(self.nodes[0:3], wait=.1)
mined = mining_node.getblock(mining_node.generate(1)[0],True)["tx"]
- sync_blocks(self.nodes[0:3],.1)
+ sync_blocks(self.nodes[0:3], wait=.1)
# update which txouts are confirmed
newmem = []
for utx in self.memutxo:
@@ -238,18 +232,21 @@ class EstimateFeeTest(BitcoinTestFramework):
self.memutxo = newmem
def run_test(self):
+ # Make log handler available to helper functions
+ global log
+ log = self.log
self.fees_per_kb = []
self.memutxo = []
self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting
- print("Will output estimates for 1/2/3/6/15/25 blocks")
+ self.log.info("Will output estimates for 1/2/3/6/15/25 blocks")
for i in range(2):
- print("Creating transactions and mining them with a block size that can't keep up")
+ self.log.info("Creating transactions and mining them with a block size that can't keep up")
# Create transactions and mine 10 small blocks with node 2, but create txs faster than we can mine
self.transact_and_mine(10, self.nodes[2])
check_estimates(self.nodes[1], self.fees_per_kb, 14)
- print("Creating transactions and mining them at a block size that is just big enough")
+ self.log.info("Creating transactions and mining them at a block size that is just big enough")
# Generate transactions while mining 10 more blocks, this time with node1
# which mines blocks with capacity just above the rate that transactions are being created
self.transact_and_mine(10, self.nodes[1])
@@ -259,8 +256,8 @@ class EstimateFeeTest(BitcoinTestFramework):
while len(self.nodes[1].getrawmempool()) > 0:
self.nodes[1].generate(1)
- sync_blocks(self.nodes[0:3],.1)
- print("Final estimates after emptying mempools")
+ sync_blocks(self.nodes[0:3], wait=.1)
+ self.log.info("Final estimates after emptying mempools")
check_estimates(self.nodes[1], self.fees_per_kb, 2)
if __name__ == '__main__':
diff --git a/qa/rpc-tests/test_framework/__init__.py b/test/functional/test_framework/__init__.py
index e69de29bb2..e69de29bb2 100644
--- a/qa/rpc-tests/test_framework/__init__.py
+++ b/test/functional/test_framework/__init__.py
diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py
new file mode 100644
index 0000000000..96bebe1ea1
--- /dev/null
+++ b/test/functional/test_framework/address.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Encode and decode BASE58, P2PKH and P2SH addresses."""
+
+from .script import hash256, hash160, sha256, CScript, OP_0
+from .util import bytes_to_hex_str, hex_str_to_bytes
+
+chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
+
+def byte_to_base58(b, version):
+ result = ''
+ str = bytes_to_hex_str(b)
+ str = bytes_to_hex_str(chr(version).encode('latin-1')) + str
+ checksum = bytes_to_hex_str(hash256(hex_str_to_bytes(str)))
+ str += checksum[:8]
+ value = int('0x'+str,0)
+ while value > 0:
+ result = chars[value % 58] + result
+ value //= 58
+ while (str[:2] == '00'):
+ result = chars[0] + result
+ str = str[2:]
+ return result
+
+# TODO: def base58_decode
+
+def keyhash_to_p2pkh(hash, main = False):
+ assert (len(hash) == 20)
+ version = 0 if main else 111
+ return byte_to_base58(hash, version)
+
+def scripthash_to_p2sh(hash, main = False):
+ assert (len(hash) == 20)
+ version = 5 if main else 196
+ return byte_to_base58(hash, version)
+
+def key_to_p2pkh(key, main = False):
+ key = check_key(key)
+ return keyhash_to_p2pkh(hash160(key), main)
+
+def script_to_p2sh(script, main = False):
+ script = check_script(script)
+ return scripthash_to_p2sh(hash160(script), main)
+
+def key_to_p2sh_p2wpkh(key, main = False):
+ key = check_key(key)
+ p2shscript = CScript([OP_0, hash160(key)])
+ return script_to_p2sh(p2shscript, main)
+
+def script_to_p2sh_p2wsh(script, main = False):
+ script = check_script(script)
+ p2shscript = CScript([OP_0, sha256(script)])
+ return script_to_p2sh(p2shscript, main)
+
+def check_key(key):
+ if (type(key) is str):
+ key = hex_str_to_bytes(key) # Assuming this is hex string
+ if (type(key) is bytes and (len(key) == 33 or len(key) == 65)):
+ return key
+ assert(False)
+
+def check_script(script):
+ if (type(script) is str):
+ script = hex_str_to_bytes(script) # Assuming this is hex string
+ if (type(script) is bytes or type(script) is CScript):
+ return script
+ assert(False)
diff --git a/qa/rpc-tests/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py
index d095a56ce7..dfcc524313 100644
--- a/qa/rpc-tests/test_framework/authproxy.py
+++ b/test/functional/test_framework/authproxy.py
@@ -1,37 +1,36 @@
-
-"""
- Copyright 2011 Jeff Garzik
-
- AuthServiceProxy has the following improvements over python-jsonrpc's
- ServiceProxy class:
-
- - HTTP connections persist for the life of the AuthServiceProxy object
- (if server supports HTTP/1.1)
- - sends protocol 'version', per JSON-RPC 1.1
- - sends proper, incrementing 'id'
- - sends Basic HTTP authentication headers
- - parses all JSON numbers that look like floats as Decimal
- - uses standard Python json lib
-
- Previous copyright, from python-jsonrpc/jsonrpc/proxy.py:
-
- Copyright (c) 2007 Jan-Klaas Kollhof
-
- This file is part of jsonrpc.
-
- jsonrpc is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this software; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# Copyright (c) 2011 Jeff Garzik
+#
+# Previous copyright, from python-jsonrpc/jsonrpc/proxy.py:
+#
+# Copyright (c) 2007 Jan-Klaas Kollhof
+#
+# This file is part of jsonrpc.
+#
+# jsonrpc is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this software; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""HTTP proxy for opening RPC connection to bitcoind.
+
+AuthServiceProxy has the following improvements over python-jsonrpc's
+ServiceProxy class:
+
+- HTTP connections persist for the life of the AuthServiceProxy object
+ (if server supports HTTP/1.1)
+- sends protocol 'version', per JSON-RPC 1.1
+- sends proper, incrementing 'id'
+- sends Basic HTTP authentication headers
+- parses all JSON numbers that look like floats as Decimal
+- uses standard Python json lib
"""
try:
@@ -42,6 +41,8 @@ import base64
import decimal
import json
import logging
+import socket
+import time
try:
import urllib.parse as urlparse
except ImportError:
@@ -55,7 +56,11 @@ log = logging.getLogger("BitcoinRPC")
class JSONRPCException(Exception):
def __init__(self, rpc_error):
- Exception.__init__(self)
+ try:
+ errmsg = '%(message)s (%(code)i)' % rpc_error
+ except (KeyError, TypeError):
+ errmsg = ''
+ Exception.__init__(self, errmsg)
self.error = rpc_error
@@ -126,20 +131,23 @@ class AuthServiceProxy(object):
return self._get_response()
else:
raise
- except BrokenPipeError:
- # Python 3.5+ raises this instead of BadStatusLine when the connection was reset
+ except (BrokenPipeError,ConnectionResetError):
+ # Python 3.5+ raises BrokenPipeError instead of BadStatusLine when the connection was reset
+ # ConnectionResetError happens on FreeBSD with Python 3.4
self.__conn.close()
self.__conn.request(method, path, postdata, headers)
return self._get_response()
- def __call__(self, *args):
+ def __call__(self, *args, **argsn):
AuthServiceProxy.__id_count += 1
log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self._service_name,
json.dumps(args, default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))
+ if args and argsn:
+ raise ValueError('Cannot handle both named and positional arguments')
postdata = json.dumps({'version': '1.1',
'method': self._service_name,
- 'params': args,
+ 'params': args or argsn,
'id': AuthServiceProxy.__id_count}, default=EncodeDecimal, ensure_ascii=self.ensure_ascii)
response = self._request('POST', self.__url.path, postdata.encode('utf-8'))
if response['error'] is not None:
@@ -156,7 +164,16 @@ class AuthServiceProxy(object):
return self._request('POST', self.__url.path, postdata.encode('utf-8'))
def _get_response(self):
- http_response = self.__conn.getresponse()
+ req_start_time = time.time()
+ try:
+ http_response = self.__conn.getresponse()
+ except socket.timeout as e:
+ raise JSONRPCException({
+ 'code': -344,
+ 'message': '%r RPC took longer than %f seconds. Consider '
+ 'using larger timeout for calls that take '
+ 'longer to return.' % (self._service_name,
+ self.__conn.timeout)})
if http_response is None:
raise JSONRPCException({
'code': -342, 'message': 'missing HTTP response from server'})
@@ -168,8 +185,9 @@ class AuthServiceProxy(object):
responsedata = http_response.read().decode('utf8')
response = json.loads(responsedata, parse_float=decimal.Decimal)
+ elapsed = time.time() - req_start_time
if "error" in response and response["error"] is None:
- log.debug("<-%s- %s"%(response["id"], json.dumps(response["result"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))
+ log.debug("<-%s- [%.6f] %s"%(response["id"], elapsed, json.dumps(response["result"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))
else:
- log.debug("<-- "+responsedata)
+ log.debug("<-- [%.6f] %s"%(elapsed,responsedata))
return response
diff --git a/qa/rpc-tests/test_framework/bignum.py b/test/functional/test_framework/bignum.py
index ef800e4d57..024611da6e 100644
--- a/qa/rpc-tests/test_framework/bignum.py
+++ b/test/functional/test_framework/bignum.py
@@ -1,15 +1,11 @@
#!/usr/bin/env python3
#
-# bignum.py
-#
-# This file is copied from python-bitcoinlib.
-#
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-
-"""Bignum routines"""
+"""Big number routines.
+This file is copied from python-bitcoinlib.
+"""
import struct
diff --git a/qa/rpc-tests/test_framework/blockstore.py b/test/functional/test_framework/blockstore.py
index 6120dd574b..4cfd682bb5 100644
--- a/qa/rpc-tests/test_framework/blockstore.py
+++ b/test/functional/test_framework/blockstore.py
@@ -1,16 +1,25 @@
#!/usr/bin/env python3
-# BlockStore: a helper class that keeps a map of blocks and implements
-# helper functions for responding to getheaders and getdata,
-# and for constructing a getheaders message
-#
+# Copyright (c) 2015-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.
+"""BlockStore and TxStore helper classes."""
from .mininode import *
from io import BytesIO
-import dbm.ndbm
+import dbm.dumb as dbmd
+
+logger = logging.getLogger("TestFramework.blockstore")
class BlockStore(object):
+ """BlockStore helper class.
+
+ BlockStore keeps a map of blocks and implements helper functions for
+ responding to getheaders and getdata, and for constructing a getheaders
+ message.
+ """
+
def __init__(self, datadir):
- self.blockDB = dbm.ndbm.open(datadir + "/blocks", 'c')
+ self.blockDB = dbmd.open(datadir + "/blocks", 'c')
self.currentBlock = 0
self.headers_map = dict()
@@ -79,7 +88,7 @@ class BlockStore(object):
try:
self.blockDB[repr(block.sha256)] = bytes(block.serialize())
except TypeError as e:
- print("Unexpected error: ", sys.exc_info()[0], e.args)
+ logger.exception("Unexpected error")
self.currentBlock = block.sha256
self.headers_map[block.sha256] = CBlockHeader(block)
@@ -120,7 +129,7 @@ class BlockStore(object):
class TxStore(object):
def __init__(self, datadir):
- self.txDB = dbm.ndbm.open(datadir + "/transactions", 'c')
+ self.txDB = dbmd.open(datadir + "/transactions", 'c')
def close(self):
self.txDB.close()
@@ -149,7 +158,7 @@ class TxStore(object):
try:
self.txDB[repr(tx.sha256)] = bytes(tx.serialize())
except TypeError as e:
- print("Unexpected error: ", sys.exc_info()[0], e.args)
+ logger.exception("Unexpected error")
def get_transactions(self, inv):
responses = []
diff --git a/qa/rpc-tests/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index f69958823c..5dcf516dc6 100644
--- a/qa/rpc-tests/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
-# blocktools.py - utilities for manipulating blocks and transactions
# Copyright (c) 2015-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.
+"""Utilities for manipulating blocks and transactions."""
from .mininode import *
from .script import CScript, OP_TRUE, OP_CHECKSIG, OP_RETURN
@@ -25,6 +25,13 @@ def create_block(hashprev, coinbase, nTime=None):
# From BIP141
WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
+
+def get_witness_script(witness_root, witness_nonce):
+ witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(witness_nonce)))
+ output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)
+ return CScript([OP_RETURN, output_data])
+
+
# According to BIP141, blocks with witness rules active must commit to the
# hash of all in-block transactions including witness.
def add_witness_commitment(block, nonce=0):
@@ -32,14 +39,12 @@ def add_witness_commitment(block, nonce=0):
# transactions, with witnesses.
witness_nonce = nonce
witness_root = block.calc_witness_merkle_root()
- witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(witness_nonce)))
# witness_nonce should go to coinbase witness.
block.vtx[0].wit.vtxinwit = [CTxInWitness()]
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(witness_nonce)]
# witness commitment is the last OP_RETURN output in coinbase
- output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)
- block.vtx[0].vout.append(CTxOut(0, CScript([OP_RETURN, output_data])))
+ block.vtx[0].vout.append(CTxOut(0, get_witness_script(witness_root, witness_nonce)))
block.vtx[0].rehash()
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
diff --git a/qa/rpc-tests/test_framework/comptool.py b/test/functional/test_framework/comptool.py
index 7c92d3f828..9f062865a3 100755
--- a/qa/rpc-tests/test_framework/comptool.py
+++ b/test/functional/test_framework/comptool.py
@@ -2,34 +2,33 @@
# Copyright (c) 2015-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.
+"""Compare two or more bitcoinds to each other.
+
+To use, create a class that implements get_tests(), and pass it in
+as the test generator to TestManager. get_tests() should be a python
+generator that returns TestInstance objects. See below for definition.
+
+TestNode behaves as follows:
+ Configure with a BlockStore and TxStore
+ on_inv: log the message but don't request
+ on_headers: log the chain tip
+ on_pong: update ping response map (for synchronization)
+ on_getheaders: provide headers via BlockStore
+ on_getdata: provide blocks via BlockStore
+"""
from .mininode import *
from .blockstore import BlockStore, TxStore
from .util import p2p_port
-'''
-This is a tool for comparing two or more bitcoinds to each other
-using a script provided.
-
-To use, create a class that implements get_tests(), and pass it in
-as the test generator to TestManager. get_tests() should be a python
-generator that returns TestInstance objects. See below for definition.
-'''
+import logging
-# TestNode behaves as follows:
-# Configure with a BlockStore and TxStore
-# on_inv: log the message but don't request
-# on_headers: log the chain tip
-# on_pong: update ping response map (for synchronization)
-# on_getheaders: provide headers via BlockStore
-# on_getdata: provide blocks via BlockStore
+logger=logging.getLogger("TestFramework.comptool")
global mininode_lock
class RejectResult(object):
- '''
- Outcome that expects rejection of a transaction or block.
- '''
+ """Outcome that expects rejection of a transaction or block."""
def __init__(self, code, reason=b''):
self.code = code
self.reason = reason
@@ -43,7 +42,7 @@ class RejectResult(object):
class TestNode(NodeConnCB):
def __init__(self, block_store, tx_store):
- NodeConnCB.__init__(self)
+ super().__init__()
self.conn = None
self.bestblockhash = None
self.block_store = block_store
@@ -111,6 +110,11 @@ class TestNode(NodeConnCB):
m.locator = self.block_store.get_locator(self.bestblockhash)
self.conn.send_message(m)
+ def send_header(self, header):
+ m = msg_headers()
+ m.headers.append(header)
+ self.conn.send_message(m)
+
# This assumes BIP31
def send_ping(self, nonce):
self.pingMap[nonce] = True
@@ -188,9 +192,7 @@ class TestManager(object):
return wait_until(disconnected, timeout=10)
def wait_for_verack(self):
- def veracked():
- return all(node.verack_received for node in self.test_nodes)
- return wait_until(veracked, timeout=10)
+ return all(node.wait_for_verack() for node in self.test_nodes)
def wait_for_pings(self, counter):
def received_pongs():
@@ -209,7 +211,6 @@ class TestManager(object):
# --> error if not requested
if not wait_until(blocks_requested, attempts=20*num_blocks):
- # print [ c.cb.block_request_map for c in self.connections ]
raise AssertionError("Not all nodes requested block")
# Send getheaders message
@@ -231,7 +232,6 @@ class TestManager(object):
# --> error if not requested
if not wait_until(transaction_requested, attempts=20*num_events):
- # print [ c.cb.tx_request_map for c in self.connections ]
raise AssertionError("Not all nodes requested transaction")
# Get the mempool
@@ -258,13 +258,12 @@ class TestManager(object):
if c.cb.bestblockhash == blockhash:
return False
if blockhash not in c.cb.block_reject_map:
- print('Block not in reject map: %064x' % (blockhash))
+ logger.error('Block not in reject map: %064x' % (blockhash))
return False
if not outcome.match(c.cb.block_reject_map[blockhash]):
- print('Block rejected with %s instead of expected %s: %064x' % (c.cb.block_reject_map[blockhash], outcome, blockhash))
+ logger.error('Block rejected with %s instead of expected %s: %064x' % (c.cb.block_reject_map[blockhash], outcome, blockhash))
return False
elif ((c.cb.bestblockhash == blockhash) != outcome):
- # print c.cb.bestblockhash, blockhash, outcome
return False
return True
@@ -280,19 +279,17 @@ class TestManager(object):
if outcome is None:
# Make sure the mempools agree with each other
if c.cb.lastInv != self.connections[0].cb.lastInv:
- # print c.rpc.getrawmempool()
return False
elif isinstance(outcome, RejectResult): # Check that tx was rejected w/ code
if txhash in c.cb.lastInv:
return False
if txhash not in c.cb.tx_reject_map:
- print('Tx not in reject map: %064x' % (txhash))
+ logger.error('Tx not in reject map: %064x' % (txhash))
return False
if not outcome.match(c.cb.tx_reject_map[txhash]):
- print('Tx rejected with %s instead of expected %s: %064x' % (c.cb.tx_reject_map[txhash], outcome, txhash))
+ logger.error('Tx rejected with %s instead of expected %s: %064x' % (c.cb.tx_reject_map[txhash], outcome, txhash))
return False
elif ((txhash in c.cb.lastInv) != outcome):
- # print c.rpc.getrawmempool(), c.cb.lastInv
return False
return True
@@ -345,8 +342,16 @@ class TestManager(object):
# Either send inv's to each node and sync, or add
# to invqueue for later inv'ing.
if (test_instance.sync_every_block):
- [ c.cb.send_inv(block) for c in self.connections ]
- self.sync_blocks(block.sha256, 1)
+ # if we expect success, send inv and sync every block
+ # if we expect failure, just push the block and see what happens.
+ if outcome == True:
+ [ c.cb.send_inv(block) for c in self.connections ]
+ self.sync_blocks(block.sha256, 1)
+ else:
+ [ c.send_message(msg_block(block)) for c in self.connections ]
+ [ c.cb.send_ping(self.ping_counter) for c in self.connections ]
+ self.wait_for_pings(self.ping_counter)
+ self.ping_counter += 1
if (not self.check_results(tip, outcome)):
raise AssertionError("Test failed at test %d" % test_number)
else:
@@ -354,6 +359,8 @@ class TestManager(object):
elif isinstance(b_or_t, CBlockHeader):
block_header = b_or_t
self.block_store.add_header(block_header)
+ [ c.cb.send_header(block_header) for c in self.connections ]
+
else: # Tx test runner
assert(isinstance(b_or_t, CTransaction))
tx = b_or_t
@@ -392,7 +399,7 @@ class TestManager(object):
if (not self.check_mempool(tx.sha256, tx_outcome)):
raise AssertionError("Mempool test failed at test %d" % test_number)
- print("Test %d: PASS" % test_number, [ c.rpc.getblockcount() for c in self.connections ])
+ logger.info("Test %d: PASS" % test_number)
test_number += 1
[ c.disconnect_node() for c in self.connections ]
diff --git a/qa/rpc-tests/test_framework/coverage.py b/test/functional/test_framework/coverage.py
index 23fce61014..3f87ef91f6 100644
--- a/qa/rpc-tests/test_framework/coverage.py
+++ b/test/functional/test_framework/coverage.py
@@ -2,15 +2,12 @@
# Copyright (c) 2015-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.
+"""Utilities for doing coverage analysis on the RPC interface.
-"""
-This module contains utilities for doing coverage analysis on the RPC
-interface.
-
-It provides a way to track which RPC commands are exercised during
+Provides a way to track which RPC commands are exercised during
testing.
-
"""
+
import os
@@ -50,7 +47,7 @@ class AuthServiceProxyWrapper(object):
rpc_method = self.auth_service_proxy_instance._service_name
if self.coverage_logfile:
- with open(self.coverage_logfile, 'a+') as f:
+ with open(self.coverage_logfile, 'a+', encoding='utf8') as f:
f.write("%s\n" % rpc_method)
return return_val
@@ -100,7 +97,7 @@ def write_all_rpc_commands(dirname, node):
if line and not line.startswith('='):
commands.add("%s\n" % line.split()[0])
- with open(filename, 'w') as f:
+ with open(filename, 'w', encoding='utf8') as f:
f.writelines(list(commands))
return True
diff --git a/qa/rpc-tests/test_framework/key.py b/test/functional/test_framework/key.py
index ba3038fe04..85a6158a2f 100644
--- a/qa/rpc-tests/test_framework/key.py
+++ b/test/functional/test_framework/key.py
@@ -1,14 +1,10 @@
# Copyright (c) 2011 Sam Rushing
-#
-# key.py - OpenSSL wrapper
-#
-# This file is modified from python-bitcoinlib.
-#
-
-"""ECC secp256k1 crypto routines
+"""ECC secp256k1 OpenSSL wrapper.
WARNING: This module does not mlock() secrets; your private keys may end up on
disk in swap! Use with caution!
+
+This file is modified from python-bitcoinlib.
"""
import ctypes
@@ -75,6 +71,9 @@ ssl.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p,
# this specifies the curve used with ECDSA.
NID_secp256k1 = 714 # from openssl/obj_mac.h
+SECP256K1_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
+SECP256K1_ORDER_HALF = SECP256K1_ORDER // 2
+
# Thx to Sam Devlin for the ctypes magic 64-bit fix.
def _check_result(val, func, args):
if val == 0:
@@ -147,7 +146,7 @@ class CECKey(object):
r = self.get_raw_ecdh_key(other_pubkey)
return kdf(r)
- def sign(self, hash):
+ def sign(self, hash, low_s = True):
# FIXME: need unit tests for below cases
if not isinstance(hash, bytes):
raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
@@ -159,7 +158,25 @@ class CECKey(object):
mb_sig = ctypes.create_string_buffer(sig_size0.value)
result = ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k)
assert 1 == result
- return mb_sig.raw[:sig_size0.value]
+ assert mb_sig.raw[0] == 0x30
+ assert mb_sig.raw[1] == sig_size0.value - 2
+ total_size = mb_sig.raw[1]
+ assert mb_sig.raw[2] == 2
+ r_size = mb_sig.raw[3]
+ assert mb_sig.raw[4 + r_size] == 2
+ s_size = mb_sig.raw[5 + r_size]
+ s_value = int.from_bytes(mb_sig.raw[6+r_size:6+r_size+s_size], byteorder='big')
+ if (not low_s) or s_value <= SECP256K1_ORDER_HALF:
+ return mb_sig.raw[:sig_size0.value]
+ else:
+ low_s_value = SECP256K1_ORDER - s_value
+ low_s_bytes = (low_s_value).to_bytes(33, byteorder='big')
+ while len(low_s_bytes) > 1 and low_s_bytes[0] == 0 and low_s_bytes[1] < 0x80:
+ low_s_bytes = low_s_bytes[1:]
+ new_s_size = len(low_s_bytes)
+ new_total_size_byte = (total_size + new_s_size - s_size).to_bytes(1,byteorder='big')
+ new_s_size_byte = (new_s_size).to_bytes(1,byteorder='big')
+ return b'\x30' + new_total_size_byte + mb_sig.raw[2:5+r_size] + new_s_size_byte + low_s_bytes
def verify(self, hash, sig):
"""Verify a DER signature"""
diff --git a/qa/rpc-tests/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index cdd5292cd6..fb3ed1473a 100755
--- a/qa/rpc-tests/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -4,45 +4,46 @@
# Copyright (c) 2010-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.
+"""Bitcoin P2P network half-a-node.
+
+This python code was modified from ArtForz' public domain half-a-node, as
+found in the mini-node branch of http://github.com/jgarzik/pynode.
+
+NodeConn: an object which manages p2p connectivity to a bitcoin node
+NodeConnCB: a base class that describes the interface for receiving
+ callbacks with network messages from a NodeConn
+CBlock, CTransaction, CBlockHeader, CTxIn, CTxOut, etc....:
+ data structures that should map to corresponding structures in
+ bitcoin/primitives
+msg_block, msg_tx, msg_headers, etc.:
+ data structures that represent network messages
+ser_*, deser_*: functions that handle serialization/deserialization
+"""
-#
-# mininode.py - Bitcoin P2P network half-a-node
-#
-# This python code was modified from ArtForz' public domain half-a-node, as
-# found in the mini-node branch of http://github.com/jgarzik/pynode.
-#
-# NodeConn: an object which manages p2p connectivity to a bitcoin node
-# NodeConnCB: a base class that describes the interface for receiving
-# callbacks with network messages from a NodeConn
-# CBlock, CTransaction, CBlockHeader, CTxIn, CTxOut, etc....:
-# data structures that should map to corresponding structures in
-# bitcoin/primitives
-# msg_block, msg_tx, msg_headers, etc.:
-# data structures that represent network messages
-# ser_*, deser_*: functions that handle serialization/deserialization
-
-
-import struct
-import socket
import asyncore
-import time
-import sys
-import random
-from .util import hex_str_to_bytes, bytes_to_hex_str
-from io import BytesIO
from codecs import encode
+from collections import defaultdict
+import copy
import hashlib
-from threading import RLock
-from threading import Thread
+from io import BytesIO
import logging
-import copy
+import random
+import socket
+import struct
+import sys
+import time
+from threading import RLock, Thread
+
+from test_framework.siphash import siphash256
+from test_framework.util import hex_str_to_bytes, bytes_to_hex_str
BIP0031_VERSION = 60000
-MY_VERSION = 60001 # past bip-31 for ping/pong
+MY_VERSION = 70014 # past bip-31 for ping/pong
MY_SUBVERSION = b"/python-mininode-tester:0.0.3/"
+MY_RELAY = 1 # from version 70001 onwards, fRelay should be appended to version messages (BIP37)
MAX_INV_SZ = 50000
-MAX_BLOCK_SIZE = 1000000
+MAX_BLOCK_BASE_SIZE = 1000000
COIN = 100000000 # 1 btc in satoshis
@@ -51,8 +52,10 @@ NODE_GETUTXO = (1 << 1)
NODE_BLOOM = (1 << 2)
NODE_WITNESS = (1 << 3)
+logger = logging.getLogger("TestFramework.mininode")
+
# Keep our own socket map for asyncore, so that we can track disconnects
-# ourselves (to workaround an issue with closing an asyncore socket when
+# ourselves (to workaround an issue with closing an asyncore socket when
# using select)
mininode_socket_map = dict()
@@ -74,8 +77,19 @@ def ripemd160(s):
def hash256(s):
return sha256(sha256(s))
+def ser_compact_size(l):
+ r = b""
+ if l < 253:
+ r = struct.pack("B", l)
+ elif l < 0x10000:
+ r = struct.pack("<BH", 253, l)
+ elif l < 0x100000000:
+ r = struct.pack("<BI", 254, l)
+ else:
+ r = struct.pack("<BQ", 255, l)
+ return r
-def deser_string(f):
+def deser_compact_size(f):
nit = struct.unpack("<B", f.read(1))[0]
if nit == 253:
nit = struct.unpack("<H", f.read(2))[0]
@@ -83,16 +97,14 @@ def deser_string(f):
nit = struct.unpack("<I", f.read(4))[0]
elif nit == 255:
nit = struct.unpack("<Q", f.read(8))[0]
+ return nit
+
+def deser_string(f):
+ nit = deser_compact_size(f)
return f.read(nit)
def ser_string(s):
- if len(s) < 253:
- return struct.pack("B", len(s)) + s
- elif len(s) < 0x10000:
- return struct.pack("<BH", 253, len(s)) + s
- elif len(s) < 0x100000000:
- return struct.pack("<BI", 254, len(s)) + s
- return struct.pack("<BQ", 255, len(s)) + s
+ return ser_compact_size(len(s)) + s
def deser_uint256(f):
r = 0
@@ -125,13 +137,7 @@ def uint256_from_compact(c):
def deser_vector(f, c):
- nit = struct.unpack("<B", f.read(1))[0]
- if nit == 253:
- nit = struct.unpack("<H", f.read(2))[0]
- elif nit == 254:
- nit = struct.unpack("<I", f.read(4))[0]
- elif nit == 255:
- nit = struct.unpack("<Q", f.read(8))[0]
+ nit = deser_compact_size(f)
r = []
for i in range(nit):
t = c()
@@ -144,15 +150,7 @@ def deser_vector(f, c):
# entries in the vector (we use this for serializing the vector of transactions
# for a witness block).
def ser_vector(l, ser_function_name=None):
- r = b""
- if len(l) < 253:
- r = struct.pack("B", len(l))
- elif len(l) < 0x10000:
- r = struct.pack("<BH", 253, len(l))
- elif len(l) < 0x100000000:
- r = struct.pack("<BI", 254, len(l))
- else:
- r = struct.pack("<BQ", 255, len(l))
+ r = ser_compact_size(len(l))
for i in l:
if ser_function_name:
r += getattr(i, ser_function_name)()
@@ -162,13 +160,7 @@ def ser_vector(l, ser_function_name=None):
def deser_uint256_vector(f):
- nit = struct.unpack("<B", f.read(1))[0]
- if nit == 253:
- nit = struct.unpack("<H", f.read(2))[0]
- elif nit == 254:
- nit = struct.unpack("<I", f.read(4))[0]
- elif nit == 255:
- nit = struct.unpack("<Q", f.read(8))[0]
+ nit = deser_compact_size(f)
r = []
for i in range(nit):
t = deser_uint256(f)
@@ -177,28 +169,14 @@ def deser_uint256_vector(f):
def ser_uint256_vector(l):
- r = b""
- if len(l) < 253:
- r = struct.pack("B", len(l))
- elif len(l) < 0x10000:
- r = struct.pack("<BH", 253, len(l))
- elif len(l) < 0x100000000:
- r = struct.pack("<BI", 254, len(l))
- else:
- r = struct.pack("<BQ", 255, len(l))
+ r = ser_compact_size(len(l))
for i in l:
r += ser_uint256(i)
return r
def deser_string_vector(f):
- nit = struct.unpack("<B", f.read(1))[0]
- if nit == 253:
- nit = struct.unpack("<H", f.read(2))[0]
- elif nit == 254:
- nit = struct.unpack("<I", f.read(4))[0]
- elif nit == 255:
- nit = struct.unpack("<Q", f.read(8))[0]
+ nit = deser_compact_size(f)
r = []
for i in range(nit):
t = deser_string(f)
@@ -207,28 +185,14 @@ def deser_string_vector(f):
def ser_string_vector(l):
- r = b""
- if len(l) < 253:
- r = struct.pack("B", len(l))
- elif len(l) < 0x10000:
- r = struct.pack("<BH", 253, len(l))
- elif len(l) < 0x100000000:
- r = struct.pack("<BI", 254, len(l))
- else:
- r = struct.pack("<BQ", 255, len(l))
+ r = ser_compact_size(len(l))
for sv in l:
r += ser_string(sv)
return r
def deser_int_vector(f):
- nit = struct.unpack("<B", f.read(1))[0]
- if nit == 253:
- nit = struct.unpack("<H", f.read(2))[0]
- elif nit == 254:
- nit = struct.unpack("<I", f.read(4))[0]
- elif nit == 255:
- nit = struct.unpack("<Q", f.read(8))[0]
+ nit = deser_compact_size(f)
r = []
for i in range(nit):
t = struct.unpack("<i", f.read(4))[0]
@@ -237,15 +201,7 @@ def deser_int_vector(f):
def ser_int_vector(l):
- r = b""
- if len(l) < 253:
- r = struct.pack("B", len(l))
- elif len(l) < 0x10000:
- r = struct.pack("<BH", 253, len(l))
- elif len(l) < 0x100000000:
- r = struct.pack("<BI", 254, len(l))
- else:
- r = struct.pack("<BQ", 255, len(l))
+ r = ser_compact_size(len(l))
for i in l:
r += struct.pack("<i", i)
return r
@@ -294,7 +250,8 @@ class CInv(object):
1: "TX",
2: "Block",
1|MSG_WITNESS_FLAG: "WitnessTx",
- 2|MSG_WITNESS_FLAG : "WitnessBlock"
+ 2|MSG_WITNESS_FLAG : "WitnessBlock",
+ 4: "CompactBlock"
}
def __init__(self, t=0, h=0):
@@ -497,7 +454,7 @@ class CTransaction(object):
else:
self.vout = deser_vector(f, CTxOut)
if flags != 0:
- self.wit.vtxinwit = [CTxInWitness()]*len(self.vin)
+ self.wit.vtxinwit = [CTxInWitness() for i in range(len(self.vin))]
self.wit.deserialize(f)
self.nLockTime = struct.unpack("<I", f.read(4))[0]
self.sha256 = None
@@ -563,8 +520,8 @@ class CTransaction(object):
return True
def __repr__(self):
- return "CTransaction(nVersion=%i vin=%s vout=%s nLockTime=%i)" \
- % (self.nVersion, repr(self.vin), repr(self.vout), self.nLockTime)
+ return "CTransaction(nVersion=%i vin=%s vout=%s wit=%s nLockTime=%i)" \
+ % (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime)
class CBlockHeader(object):
@@ -654,7 +611,8 @@ class CBlock(CBlockHeader):
return r
# Calculate the merkle root given a vector of transaction hashes
- def get_merkle_root(self, hashes):
+ @classmethod
+ def get_merkle_root(cls, hashes):
while len(hashes) > 1:
newhashes = []
for i in range(0, len(hashes), 2):
@@ -781,6 +739,208 @@ class CAlert(object):
% (len(self.vchMsg), len(self.vchSig))
+class PrefilledTransaction(object):
+ def __init__(self, index=0, tx = None):
+ self.index = index
+ self.tx = tx
+
+ def deserialize(self, f):
+ self.index = deser_compact_size(f)
+ self.tx = CTransaction()
+ self.tx.deserialize(f)
+
+ def serialize(self, with_witness=False):
+ r = b""
+ r += ser_compact_size(self.index)
+ if with_witness:
+ r += self.tx.serialize_with_witness()
+ else:
+ r += self.tx.serialize_without_witness()
+ return r
+
+ def serialize_with_witness(self):
+ return self.serialize(with_witness=True)
+
+ def __repr__(self):
+ return "PrefilledTransaction(index=%d, tx=%s)" % (self.index, repr(self.tx))
+
+# This is what we send on the wire, in a cmpctblock message.
+class P2PHeaderAndShortIDs(object):
+ def __init__(self):
+ self.header = CBlockHeader()
+ self.nonce = 0
+ self.shortids_length = 0
+ self.shortids = []
+ self.prefilled_txn_length = 0
+ self.prefilled_txn = []
+
+ def deserialize(self, f):
+ self.header.deserialize(f)
+ self.nonce = struct.unpack("<Q", f.read(8))[0]
+ self.shortids_length = deser_compact_size(f)
+ for i in range(self.shortids_length):
+ # shortids are defined to be 6 bytes in the spec, so append
+ # two zero bytes and read it in as an 8-byte number
+ self.shortids.append(struct.unpack("<Q", f.read(6) + b'\x00\x00')[0])
+ self.prefilled_txn = deser_vector(f, PrefilledTransaction)
+ self.prefilled_txn_length = len(self.prefilled_txn)
+
+ # When using version 2 compact blocks, we must serialize with_witness.
+ def serialize(self, with_witness=False):
+ r = b""
+ r += self.header.serialize()
+ r += struct.pack("<Q", self.nonce)
+ r += ser_compact_size(self.shortids_length)
+ for x in self.shortids:
+ # We only want the first 6 bytes
+ r += struct.pack("<Q", x)[0:6]
+ if with_witness:
+ r += ser_vector(self.prefilled_txn, "serialize_with_witness")
+ else:
+ r += ser_vector(self.prefilled_txn)
+ return r
+
+ def __repr__(self):
+ return "P2PHeaderAndShortIDs(header=%s, nonce=%d, shortids_length=%d, shortids=%s, prefilled_txn_length=%d, prefilledtxn=%s" % (repr(self.header), self.nonce, self.shortids_length, repr(self.shortids), self.prefilled_txn_length, repr(self.prefilled_txn))
+
+# P2P version of the above that will use witness serialization (for compact
+# block version 2)
+class P2PHeaderAndShortWitnessIDs(P2PHeaderAndShortIDs):
+ def serialize(self):
+ return super(P2PHeaderAndShortWitnessIDs, self).serialize(with_witness=True)
+
+# Calculate the BIP 152-compact blocks shortid for a given transaction hash
+def calculate_shortid(k0, k1, tx_hash):
+ expected_shortid = siphash256(k0, k1, tx_hash)
+ expected_shortid &= 0x0000ffffffffffff
+ return expected_shortid
+
+# This version gets rid of the array lengths, and reinterprets the differential
+# encoding into indices that can be used for lookup.
+class HeaderAndShortIDs(object):
+ def __init__(self, p2pheaders_and_shortids = None):
+ self.header = CBlockHeader()
+ self.nonce = 0
+ self.shortids = []
+ self.prefilled_txn = []
+ self.use_witness = False
+
+ if p2pheaders_and_shortids != None:
+ self.header = p2pheaders_and_shortids.header
+ self.nonce = p2pheaders_and_shortids.nonce
+ self.shortids = p2pheaders_and_shortids.shortids
+ last_index = -1
+ for x in p2pheaders_and_shortids.prefilled_txn:
+ self.prefilled_txn.append(PrefilledTransaction(x.index + last_index + 1, x.tx))
+ last_index = self.prefilled_txn[-1].index
+
+ def to_p2p(self):
+ if self.use_witness:
+ ret = P2PHeaderAndShortWitnessIDs()
+ else:
+ ret = P2PHeaderAndShortIDs()
+ ret.header = self.header
+ ret.nonce = self.nonce
+ ret.shortids_length = len(self.shortids)
+ ret.shortids = self.shortids
+ ret.prefilled_txn_length = len(self.prefilled_txn)
+ ret.prefilled_txn = []
+ last_index = -1
+ for x in self.prefilled_txn:
+ ret.prefilled_txn.append(PrefilledTransaction(x.index - last_index - 1, x.tx))
+ last_index = x.index
+ return ret
+
+ def get_siphash_keys(self):
+ header_nonce = self.header.serialize()
+ header_nonce += struct.pack("<Q", self.nonce)
+ hash_header_nonce_as_str = sha256(header_nonce)
+ key0 = struct.unpack("<Q", hash_header_nonce_as_str[0:8])[0]
+ key1 = struct.unpack("<Q", hash_header_nonce_as_str[8:16])[0]
+ return [ key0, key1 ]
+
+ # Version 2 compact blocks use wtxid in shortids (rather than txid)
+ def initialize_from_block(self, block, nonce=0, prefill_list = [0], use_witness = False):
+ self.header = CBlockHeader(block)
+ self.nonce = nonce
+ self.prefilled_txn = [ PrefilledTransaction(i, block.vtx[i]) for i in prefill_list ]
+ self.shortids = []
+ self.use_witness = use_witness
+ [k0, k1] = self.get_siphash_keys()
+ for i in range(len(block.vtx)):
+ if i not in prefill_list:
+ tx_hash = block.vtx[i].sha256
+ if use_witness:
+ tx_hash = block.vtx[i].calc_sha256(with_witness=True)
+ self.shortids.append(calculate_shortid(k0, k1, tx_hash))
+
+ def __repr__(self):
+ return "HeaderAndShortIDs(header=%s, nonce=%d, shortids=%s, prefilledtxn=%s" % (repr(self.header), self.nonce, repr(self.shortids), repr(self.prefilled_txn))
+
+
+class BlockTransactionsRequest(object):
+
+ def __init__(self, blockhash=0, indexes = None):
+ self.blockhash = blockhash
+ self.indexes = indexes if indexes != None else []
+
+ def deserialize(self, f):
+ self.blockhash = deser_uint256(f)
+ indexes_length = deser_compact_size(f)
+ for i in range(indexes_length):
+ self.indexes.append(deser_compact_size(f))
+
+ def serialize(self):
+ r = b""
+ r += ser_uint256(self.blockhash)
+ r += ser_compact_size(len(self.indexes))
+ for x in self.indexes:
+ r += ser_compact_size(x)
+ return r
+
+ # helper to set the differentially encoded indexes from absolute ones
+ def from_absolute(self, absolute_indexes):
+ self.indexes = []
+ last_index = -1
+ for x in absolute_indexes:
+ self.indexes.append(x-last_index-1)
+ last_index = x
+
+ def to_absolute(self):
+ absolute_indexes = []
+ last_index = -1
+ for x in self.indexes:
+ absolute_indexes.append(x+last_index+1)
+ last_index = absolute_indexes[-1]
+ return absolute_indexes
+
+ def __repr__(self):
+ return "BlockTransactionsRequest(hash=%064x indexes=%s)" % (self.blockhash, repr(self.indexes))
+
+
+class BlockTransactions(object):
+
+ def __init__(self, blockhash=0, transactions = None):
+ self.blockhash = blockhash
+ self.transactions = transactions if transactions != None else []
+
+ def deserialize(self, f):
+ self.blockhash = deser_uint256(f)
+ self.transactions = deser_vector(f, CTransaction)
+
+ def serialize(self, with_witness=False):
+ r = b""
+ r += ser_uint256(self.blockhash)
+ if with_witness:
+ r += ser_vector(self.transactions, "serialize_with_witness")
+ else:
+ r += ser_vector(self.transactions)
+ return r
+
+ def __repr__(self):
+ return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions))
+
+
# Objects that correspond to messages on the wire
class msg_version(object):
command = b"version"
@@ -794,6 +954,7 @@ class msg_version(object):
self.nNonce = random.getrandbits(64)
self.strSubVer = MY_SUBVERSION
self.nStartingHeight = -1
+ self.nRelay = MY_RELAY
def deserialize(self, f):
self.nVersion = struct.unpack("<i", f.read(4))[0]
@@ -803,21 +964,32 @@ class msg_version(object):
self.nTime = struct.unpack("<q", f.read(8))[0]
self.addrTo = CAddress()
self.addrTo.deserialize(f)
+
if self.nVersion >= 106:
self.addrFrom = CAddress()
self.addrFrom.deserialize(f)
self.nNonce = struct.unpack("<Q", f.read(8))[0]
self.strSubVer = deser_string(f)
- if self.nVersion >= 209:
- self.nStartingHeight = struct.unpack("<i", f.read(4))[0]
- else:
- self.nStartingHeight = None
else:
self.addrFrom = None
self.nNonce = None
self.strSubVer = None
self.nStartingHeight = None
+ if self.nVersion >= 209:
+ self.nStartingHeight = struct.unpack("<i", f.read(4))[0]
+ else:
+ self.nStartingHeight = None
+
+ if self.nVersion >= 70001:
+ # Relay field is optional for version 70001 onwards
+ try:
+ self.nRelay = struct.unpack("<b", f.read(1))[0]
+ except:
+ self.nRelay = 0
+ else:
+ self.nRelay = 0
+
def serialize(self):
r = b""
r += struct.pack("<i", self.nVersion)
@@ -828,13 +1000,14 @@ class msg_version(object):
r += struct.pack("<Q", self.nNonce)
r += ser_string(self.strSubVer)
r += struct.pack("<i", self.nStartingHeight)
+ r += struct.pack("<b", self.nRelay)
return r
def __repr__(self):
- return 'msg_version(nVersion=%i nServices=%i nTime=%s addrTo=%s addrFrom=%s nNonce=0x%016X strSubVer=%s nStartingHeight=%i)' \
+ return 'msg_version(nVersion=%i nServices=%i nTime=%s addrTo=%s addrFrom=%s nNonce=0x%016X strSubVer=%s nStartingHeight=%i nRelay=%i)' \
% (self.nVersion, self.nServices, time.ctime(self.nTime),
repr(self.addrTo), repr(self.addrFrom), self.nNonce,
- self.strSubVer, self.nStartingHeight)
+ self.strSubVer, self.nStartingHeight, self.nRelay)
class msg_verack(object):
@@ -1184,7 +1357,9 @@ class msg_reject(object):
% (self.message, self.code, self.reason, self.data)
# Helper function
-def wait_until(predicate, attempts=float('inf'), timeout=float('inf')):
+def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf')):
+ if attempts == float('inf') and timeout == float('inf'):
+ timeout = 60
attempt = 0
elapsed = 0
@@ -1215,59 +1390,173 @@ class msg_feefilter(object):
def __repr__(self):
return "msg_feefilter(feerate=%08x)" % self.feerate
-# This is what a callback should look like for NodeConn
-# Reimplement the on_* functions to provide handling for events
+class msg_sendcmpct(object):
+ command = b"sendcmpct"
+
+ def __init__(self):
+ self.announce = False
+ self.version = 1
+
+ def deserialize(self, f):
+ self.announce = struct.unpack("<?", f.read(1))[0]
+ self.version = struct.unpack("<Q", f.read(8))[0]
+
+ def serialize(self):
+ r = b""
+ r += struct.pack("<?", self.announce)
+ r += struct.pack("<Q", self.version)
+ return r
+
+ def __repr__(self):
+ return "msg_sendcmpct(announce=%s, version=%lu)" % (self.announce, self.version)
+
+class msg_cmpctblock(object):
+ command = b"cmpctblock"
+
+ def __init__(self, header_and_shortids = None):
+ self.header_and_shortids = header_and_shortids
+
+ def deserialize(self, f):
+ self.header_and_shortids = P2PHeaderAndShortIDs()
+ self.header_and_shortids.deserialize(f)
+
+ def serialize(self):
+ r = b""
+ r += self.header_and_shortids.serialize()
+ return r
+
+ def __repr__(self):
+ return "msg_cmpctblock(HeaderAndShortIDs=%s)" % repr(self.header_and_shortids)
+
+class msg_getblocktxn(object):
+ command = b"getblocktxn"
+
+ def __init__(self):
+ self.block_txn_request = None
+
+ def deserialize(self, f):
+ self.block_txn_request = BlockTransactionsRequest()
+ self.block_txn_request.deserialize(f)
+
+ def serialize(self):
+ r = b""
+ r += self.block_txn_request.serialize()
+ return r
+
+ def __repr__(self):
+ return "msg_getblocktxn(block_txn_request=%s)" % (repr(self.block_txn_request))
+
+class msg_blocktxn(object):
+ command = b"blocktxn"
+
+ def __init__(self):
+ self.block_transactions = BlockTransactions()
+
+ def deserialize(self, f):
+ self.block_transactions.deserialize(f)
+
+ def serialize(self):
+ r = b""
+ r += self.block_transactions.serialize()
+ return r
+
+ def __repr__(self):
+ return "msg_blocktxn(block_transactions=%s)" % (repr(self.block_transactions))
+
+class msg_witness_blocktxn(msg_blocktxn):
+ def serialize(self):
+ r = b""
+ r += self.block_transactions.serialize(with_witness=True)
+ return r
+
class NodeConnCB(object):
+ """Callback and helper functions for P2P connection to a bitcoind node.
+
+ Individual testcases should subclass this and override the on_* methods
+ if they want to alter message handling behaviour.
+ """
+
def __init__(self):
- self.verack_received = False
+ # Track whether we have a P2P connection open to the node
+ self.connected = False
+ self.connection = None
+
+ # Track number of messages of each type received and the most recent
+ # message of each type
+ self.message_count = defaultdict(int)
+ self.last_message = {}
+
+ # A count of the number of ping messages we've sent to the node
+ self.ping_counter = 1
+
# deliver_sleep_time is helpful for debugging race conditions in p2p
# tests; it causes message delivery to sleep for the specified time
# before acquiring the global lock and delivering the next message.
self.deliver_sleep_time = None
+
# Remember the services our peer has advertised
self.peer_services = None
- def set_deliver_sleep_time(self, value):
- with mininode_lock:
- self.deliver_sleep_time = value
+ # Message receiving methods
- def get_deliver_sleep_time(self):
- with mininode_lock:
- return self.deliver_sleep_time
+ def deliver(self, conn, message):
+ """Receive message and dispatch message to appropriate callback.
- # Spin until verack message is received from the node.
- # Tests may want to use this as a signal that the test can begin.
- # This can be called from the testing thread, so it needs to acquire the
- # global lock.
- def wait_for_verack(self):
- while True:
- with mininode_lock:
- if self.verack_received:
- return
- time.sleep(0.05)
+ We keep a count of how many of each message type has been received
+ and the most recent message of each type.
+
+ Optionally waits for deliver_sleep_time before dispatching message.
+ """
- def deliver(self, conn, message):
deliver_sleep = self.get_deliver_sleep_time()
if deliver_sleep is not None:
time.sleep(deliver_sleep)
with mininode_lock:
try:
- getattr(self, 'on_' + message.command.decode('ascii'))(conn, message)
+ command = message.command.decode('ascii')
+ self.message_count[command] += 1
+ self.last_message[command] = message
+ getattr(self, 'on_' + command)(conn, message)
except:
print("ERROR delivering %s (%s)" % (repr(message),
sys.exc_info()[0]))
- def on_version(self, conn, message):
- if message.nVersion >= 209:
- conn.send_message(msg_verack())
- conn.ver_send = min(MY_VERSION, message.nVersion)
- if message.nVersion < 209:
- conn.ver_recv = conn.ver_send
- conn.nServices = message.nServices
+ def set_deliver_sleep_time(self, value):
+ with mininode_lock:
+ self.deliver_sleep_time = value
- def on_verack(self, conn, message):
- conn.ver_recv = conn.ver_send
- self.verack_received = True
+ def get_deliver_sleep_time(self):
+ with mininode_lock:
+ return self.deliver_sleep_time
+
+ # Callback methods. Can be overridden by subclasses in individual test
+ # cases to provide custom message handling behaviour.
+
+ def on_open(self, conn):
+ self.connected = True
+
+ def on_close(self, conn):
+ self.connected = False
+ self.connection = None
+
+ def on_addr(self, conn, message): pass
+ def on_alert(self, conn, message): pass
+ def on_block(self, conn, message): pass
+ def on_blocktxn(self, conn, message): pass
+ def on_cmpctblock(self, conn, message): pass
+ def on_feefilter(self, conn, message): pass
+ def on_getaddr(self, conn, message): pass
+ def on_getblocks(self, conn, message): pass
+ def on_getblocktxn(self, conn, message): pass
+ def on_getdata(self, conn, message): pass
+ def on_getheaders(self, conn, message): pass
+ def on_headers(self, conn, message): pass
+ def on_mempool(self, conn): pass
+ def on_pong(self, conn, message): pass
+ def on_reject(self, conn, message): pass
+ def on_sendcmpct(self, conn, message): pass
+ def on_sendheaders(self, conn, message): pass
+ def on_tx(self, conn, message): pass
def on_inv(self, conn, message):
want = msg_getdata()
@@ -1277,51 +1566,77 @@ class NodeConnCB(object):
if len(want.inv):
conn.send_message(want)
- def on_addr(self, conn, message): pass
- def on_alert(self, conn, message): pass
- def on_getdata(self, conn, message): pass
- def on_getblocks(self, conn, message): pass
- def on_tx(self, conn, message): pass
- def on_block(self, conn, message): pass
- def on_getaddr(self, conn, message): pass
- def on_headers(self, conn, message): pass
- def on_getheaders(self, conn, message): pass
def on_ping(self, conn, message):
if conn.ver_send > BIP0031_VERSION:
conn.send_message(msg_pong(message.nonce))
- def on_reject(self, conn, message): pass
- def on_close(self, conn): pass
- def on_mempool(self, conn): pass
- def on_pong(self, conn, message): pass
- def on_feefilter(self, conn, message): pass
- def on_sendheaders(self, conn, message): pass
-# More useful callbacks and functions for NodeConnCB's which have a single NodeConn
-class SingleNodeConnCB(NodeConnCB):
- def __init__(self):
- NodeConnCB.__init__(self)
- self.connection = None
- self.ping_counter = 1
- self.last_pong = msg_pong()
+ def on_verack(self, conn, message):
+ conn.ver_recv = conn.ver_send
+ self.verack_received = True
+
+ def on_version(self, conn, message):
+ if message.nVersion >= 209:
+ conn.send_message(msg_verack())
+ conn.ver_send = min(MY_VERSION, message.nVersion)
+ if message.nVersion < 209:
+ conn.ver_recv = conn.ver_send
+ conn.nServices = message.nServices
+
+ # Connection helper methods
def add_connection(self, conn):
self.connection = conn
- # Wrapper for the NodeConn's send_message function
+ def wait_for_disconnect(self, timeout=60):
+ test_function = lambda: not self.connected
+ assert wait_until(test_function, timeout=timeout)
+
+ # Message receiving helper methods
+
+ def wait_for_block(self, blockhash, timeout=60):
+ test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash
+ assert wait_until(test_function, timeout=timeout)
+
+ def wait_for_getdata(self, timeout=60):
+ test_function = lambda: self.last_message.get("getdata")
+ assert wait_until(test_function, timeout=timeout)
+
+ def wait_for_getheaders(self, timeout=60):
+ test_function = lambda: self.last_message.get("getheaders")
+ assert wait_until(test_function, timeout=timeout)
+
+ def wait_for_inv(self, expected_inv, timeout=60):
+ """Waits for an INV message and checks that the first inv object in the message was as expected."""
+ if len(expected_inv) > 1:
+ raise NotImplementedError("wait_for_inv() will only verify the first inv object")
+ test_function = lambda: self.last_message.get("inv") and \
+ self.last_message["inv"].inv[0].type == expected_inv[0].type and \
+ self.last_message["inv"].inv[0].hash == expected_inv[0].hash
+ assert wait_until(test_function, timeout=timeout)
+
+ def wait_for_verack(self, timeout=60):
+ test_function = lambda: self.message_count["verack"]
+ assert wait_until(test_function, timeout=timeout)
+
+ # Message sending helper functions
+
def send_message(self, message):
- self.connection.send_message(message)
+ if self.connection:
+ self.connection.send_message(message)
+ else:
+ logger.error("Cannot send message. No connection to node!")
- def on_pong(self, conn, message):
- self.last_pong = message
+ def send_and_ping(self, message):
+ self.send_message(message)
+ self.sync_with_ping()
# Sync up with the node
- def sync_with_ping(self, timeout=30):
- def received_pong():
- return (self.last_pong.nonce == self.ping_counter)
+ def sync_with_ping(self, timeout=60):
self.send_message(msg_ping(nonce=self.ping_counter))
- success = wait_until(received_pong, timeout)
+ test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter
+ assert wait_until(test_function, timeout=timeout)
self.ping_counter += 1
- return success
+ return True
# The actual NodeConn class
# This class provides an interface for a p2p connection to a specified node
@@ -1344,7 +1659,11 @@ class NodeConn(asyncore.dispatcher):
b"reject": msg_reject,
b"mempool": msg_mempool,
b"feefilter": msg_feefilter,
- b"sendheaders": msg_sendheaders
+ b"sendheaders": msg_sendheaders,
+ b"sendcmpct": msg_sendcmpct,
+ b"cmpctblock": msg_cmpctblock,
+ b"getblocktxn": msg_getblocktxn,
+ b"blocktxn": msg_blocktxn
}
MAGIC_BYTES = {
"mainnet": b"\xf9\xbe\xb4\xd9", # mainnet
@@ -1352,9 +1671,8 @@ class NodeConn(asyncore.dispatcher):
"regtest": b"\xfa\xbf\xb5\xda", # regtest
}
- def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK):
+ def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK, send_version=True):
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
- self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport))
self.dstaddr = dstaddr
self.dstport = dstport
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -1369,16 +1687,17 @@ class NodeConn(asyncore.dispatcher):
self.disconnect = False
self.nServices = 0
- # stuff version msg into sendbuf
- vt = msg_version()
- vt.nServices = services
- vt.addrTo.ip = self.dstaddr
- vt.addrTo.port = self.dstport
- vt.addrFrom.ip = "0.0.0.0"
- vt.addrFrom.port = 0
- self.send_message(vt, True)
- print('MiniNode: Connecting to Bitcoin Node IP # ' + dstaddr + ':' \
- + str(dstport))
+ if send_version:
+ # stuff version msg into sendbuf
+ vt = msg_version()
+ vt.nServices = services
+ vt.addrTo.ip = self.dstaddr
+ vt.addrTo.port = self.dstport
+ vt.addrFrom.ip = "0.0.0.0"
+ vt.addrFrom.port = 0
+ self.send_message(vt, True)
+
+ logger.info('Connecting to Bitcoin Node: %s:%d' % (self.dstaddr, self.dstport))
try:
self.connect((dstaddr, dstport))
@@ -1386,16 +1705,14 @@ class NodeConn(asyncore.dispatcher):
self.handle_close()
self.rpc = rpc
- def show_debug_msg(self, msg):
- self.log.debug(msg)
-
def handle_connect(self):
- self.show_debug_msg("MiniNode: Connected & Listening: \n")
- self.state = "connected"
+ if self.state != "connected":
+ logger.debug("Connected & Listening: %s:%d" % (self.dstaddr, self.dstport))
+ self.state = "connected"
+ self.cb.on_open(self)
def handle_close(self):
- self.show_debug_msg("MiniNode: Closing Connection to %s:%d... "
- % (self.dstaddr, self.dstport))
+ logger.debug("Closing connection to: %s:%d" % (self.dstaddr, self.dstport))
self.state = "closed"
self.recvbuf = b""
self.sendbuf = b""
@@ -1419,11 +1736,20 @@ class NodeConn(asyncore.dispatcher):
def writable(self):
with mininode_lock:
+ pre_connection = self.state == "connecting"
length = len(self.sendbuf)
- return (length > 0)
+ return (length > 0 or pre_connection)
def handle_write(self):
with mininode_lock:
+ # asyncore does not expose socket connection, only the first read/write
+ # event, thus we must check connection manually here to know when we
+ # actually connect
+ if self.state == "connecting":
+ self.handle_connect()
+ if not self.writable():
+ return
+
try:
sent = self.send(self.sendbuf)
except:
@@ -1468,17 +1794,14 @@ class NodeConn(asyncore.dispatcher):
t.deserialize(f)
self.got_message(t)
else:
- self.show_debug_msg("Unknown command: '" + command + "' " +
- repr(msg))
+ logger.warning("Received unknown command from %s:%d: '%s' %s" % (self.dstaddr, self.dstport, command, repr(msg)))
except Exception as e:
- print('got_data:', repr(e))
- # import traceback
- # traceback.print_tb(sys.exc_info()[2])
+ logger.exception('got_data:', repr(e))
def send_message(self, message, pushbuf=False):
if self.state != "connected" and not pushbuf:
raise IOError('Not connected, no pushbuf')
- self.show_debug_msg("Send %s" % repr(message))
+ self._log_message("send", message)
command = message.command
data = message.serialize()
tmsg = self.MAGIC_BYTES[self.network]
@@ -1500,9 +1823,19 @@ class NodeConn(asyncore.dispatcher):
self.messagemap[b'ping'] = msg_ping_prebip31
if self.last_sent + 30 * 60 < time.time():
self.send_message(self.messagemap[b'ping']())
- self.show_debug_msg("Recv %s" % repr(message))
+ self._log_message("receive", message)
self.cb.deliver(self, message)
+ def _log_message(self, direction, msg):
+ if direction == "send":
+ log_message = "Send message to "
+ elif direction == "receive":
+ log_message = "Received message from "
+ log_message += "%s:%d: %s" % (self.dstaddr, self.dstport, repr(msg)[:500])
+ if len(log_message) > 500:
+ log_message += "... (msg truncated)"
+ logger.debug(log_message)
+
def disconnect_node(self):
self.disconnect = True
diff --git a/qa/rpc-tests/test_framework/netutil.py b/test/functional/test_framework/netutil.py
index 573b06772d..45d8e22d22 100644
--- a/qa/rpc-tests/test_framework/netutil.py
+++ b/test/functional/test_framework/netutil.py
@@ -2,8 +2,10 @@
# Copyright (c) 2014-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.
+"""Linux network utilities.
-# Linux network utilities
+Roughly based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal
+"""
import sys
import socket
@@ -13,7 +15,6 @@ import array
import os
from binascii import unhexlify, hexlify
-# Roughly based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal
STATE_ESTABLISHED = '01'
STATE_SYN_SENT = '02'
STATE_SYN_RECV = '03'
@@ -58,7 +59,7 @@ def netstat(typ='tcp'):
To get pid of all network process running on system, you must run this script
as superuser
'''
- with open('/proc/net/'+typ,'r') as f:
+ with open('/proc/net/'+typ,'r',encoding='utf8') as f:
content = f.readlines()
content.pop(0)
result = []
diff --git a/qa/rpc-tests/test_framework/script.py b/test/functional/test_framework/script.py
index b46c643ccb..3d9572788e 100644
--- a/qa/rpc-tests/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -2,19 +2,11 @@
# Copyright (c) 2015-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.
+"""Functionality to build scripts, as well as SignatureHash().
-#
-# script.py
-#
-# This file is modified from python-bitcoinlib.
-#
-
-"""Scripts
-
-Functionality to build scripts, as well as SignatureHash().
+This file is modified from python-bitcoinlib.
"""
-
from .mininode import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string
from binascii import hexlify
import hashlib
@@ -882,7 +874,7 @@ def SignatureHash(script, txTo, inIdx, hashtype):
tmp = txtmp.vout[outIdx]
txtmp.vout = []
for i in range(outIdx):
- txtmp.vout.append(CTxOut())
+ txtmp.vout.append(CTxOut(-1))
txtmp.vout.append(tmp)
for i in range(len(txtmp.vin)):
diff --git a/test/functional/test_framework/siphash.py b/test/functional/test_framework/siphash.py
new file mode 100644
index 0000000000..f68ecad36b
--- /dev/null
+++ b/test/functional/test_framework/siphash.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Specialized SipHash-2-4 implementations.
+
+This implements SipHash-2-4 for 256-bit integers.
+"""
+
+def rotl64(n, b):
+ return n >> (64 - b) | (n & ((1 << (64 - b)) - 1)) << b
+
+def siphash_round(v0, v1, v2, v3):
+ v0 = (v0 + v1) & ((1 << 64) - 1)
+ v1 = rotl64(v1, 13)
+ v1 ^= v0
+ v0 = rotl64(v0, 32)
+ v2 = (v2 + v3) & ((1 << 64) - 1)
+ v3 = rotl64(v3, 16)
+ v3 ^= v2
+ v0 = (v0 + v3) & ((1 << 64) - 1)
+ v3 = rotl64(v3, 21)
+ v3 ^= v0
+ v2 = (v2 + v1) & ((1 << 64) - 1)
+ v1 = rotl64(v1, 17)
+ v1 ^= v2
+ v2 = rotl64(v2, 32)
+ return (v0, v1, v2, v3)
+
+def siphash256(k0, k1, h):
+ n0 = h & ((1 << 64) - 1)
+ n1 = (h >> 64) & ((1 << 64) - 1)
+ n2 = (h >> 128) & ((1 << 64) - 1)
+ n3 = (h >> 192) & ((1 << 64) - 1)
+ v0 = 0x736f6d6570736575 ^ k0
+ v1 = 0x646f72616e646f6d ^ k1
+ v2 = 0x6c7967656e657261 ^ k0
+ v3 = 0x7465646279746573 ^ k1 ^ n0
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0 ^= n0
+ v3 ^= n1
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0 ^= n1
+ v3 ^= n2
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0 ^= n2
+ v3 ^= n3
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0 ^= n3
+ v3 ^= 0x2000000000000000
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0 ^= 0x2000000000000000
+ v2 ^= 0xFF
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)
+ return v0 ^ v1 ^ v2 ^ v3
diff --git a/qa/rpc-tests/test_framework/socks5.py b/test/functional/test_framework/socks5.py
index 372f5ed605..a08b03ed24 100644
--- a/qa/rpc-tests/test_framework/socks5.py
+++ b/test/functional/test_framework/socks5.py
@@ -2,12 +2,12 @@
# Copyright (c) 2015-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.
-'''
-Dummy Socks5 server for testing.
-'''
+"""Dummy Socks5 server for testing."""
import socket, threading, queue
-import traceback, sys
+import logging
+
+logger = logging.getLogger("TestFramework.socks5")
### Protocol constants
class Command:
@@ -20,7 +20,7 @@ class AddressType:
### Utility functions
def recvall(s, n):
- '''Receive n bytes from a socket, or fail'''
+ """Receive n bytes from a socket, or fail."""
rv = bytearray()
while n > 0:
d = s.recv(n)
@@ -32,7 +32,7 @@ def recvall(s, n):
### Implementation classes
class Socks5Configuration(object):
- '''Proxy configuration'''
+ """Proxy configuration."""
def __init__(self):
self.addr = None # Bind address (must be set)
self.af = socket.AF_INET # Bind address family
@@ -40,7 +40,7 @@ class Socks5Configuration(object):
self.auth = False # Support authentication
class Socks5Command(object):
- '''Information about an incoming socks5 command'''
+ """Information about an incoming socks5 command."""
def __init__(self, cmd, atyp, addr, port, username, password):
self.cmd = cmd # Command (one of Command.*)
self.atyp = atyp # Address type (one of AddressType.*)
@@ -58,9 +58,7 @@ class Socks5Connection(object):
self.peer = peer
def handle(self):
- '''
- Handle socks5 request according to RFC1928
- '''
+ """Handle socks5 request according to RFC192."""
try:
# Verify socks version
ver = recvall(self.conn, 1)[0]
@@ -116,10 +114,10 @@ class Socks5Connection(object):
cmdin = Socks5Command(cmd, atyp, addr, port, username, password)
self.serv.queue.put(cmdin)
- print('Proxy: ', cmdin)
+ logger.info('Proxy: %s', cmdin)
# Fall through to disconnect
except Exception as e:
- traceback.print_exc(file=sys.stderr)
+ logger.exception("socks5 request handling failed.")
self.serv.queue.put(e)
finally:
self.conn.close()
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
new file mode 100755
index 0000000000..8d8139e4e4
--- /dev/null
+++ b/test/functional/test_framework/test_framework.py
@@ -0,0 +1,372 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+"""Base class for RPC testing."""
+
+from collections import deque
+import logging
+import optparse
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import time
+
+from .util import (
+ PortSeed,
+ MAX_NODES,
+ bitcoind_processes,
+ check_json_precision,
+ connect_nodes_bi,
+ disable_mocktime,
+ disconnect_nodes,
+ enable_coverage,
+ enable_mocktime,
+ get_mocktime,
+ get_rpc_proxy,
+ initialize_datadir,
+ log_filename,
+ p2p_port,
+ rpc_url,
+ set_node_times,
+ start_node,
+ start_nodes,
+ stop_node,
+ stop_nodes,
+ sync_blocks,
+ sync_mempools,
+ wait_for_bitcoind_start,
+)
+from .authproxy import JSONRPCException
+
+class BitcoinTestFramework(object):
+ """Base class for a bitcoin test script.
+
+ Individual bitcoin test scripts should subclass this class and override the following methods:
+
+ - __init__()
+ - add_options()
+ - setup_chain()
+ - setup_network()
+ - run_test()
+
+ The main() method should not be overridden.
+
+ This class also contains various public and private helper methods."""
+
+ # Methods to override in subclass test scripts.
+
+ TEST_EXIT_PASSED = 0
+ TEST_EXIT_FAILED = 1
+ TEST_EXIT_SKIPPED = 77
+
+ def __init__(self):
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+ self.nodes = None
+
+ def add_options(self, parser):
+ pass
+
+ def setup_chain(self):
+ self.log.info("Initializing test directory "+self.options.tmpdir)
+ if self.setup_clean_chain:
+ self._initialize_chain_clean(self.options.tmpdir, self.num_nodes)
+ else:
+ self._initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir)
+
+ def setup_network(self):
+ self.setup_nodes()
+
+ # Connect the nodes as a "chain". This allows us
+ # to split the network between nodes 1 and 2 to get
+ # two halves that can work on competing chains.
+ for i in range(self.num_nodes - 1):
+ connect_nodes_bi(self.nodes, i, i + 1)
+ self.sync_all()
+
+ def setup_nodes(self):
+ extra_args = None
+ if hasattr(self, "extra_args"):
+ extra_args = self.extra_args
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+
+ def run_test(self):
+ raise NotImplementedError
+
+ # Main function. This should not be overridden by the subclass test scripts.
+
+ def main(self):
+
+ parser = optparse.OptionParser(usage="%prog [options]")
+ parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
+ help="Leave bitcoinds and test.* datadir on exit or error")
+ parser.add_option("--noshutdown", dest="noshutdown", default=False, action="store_true",
+ help="Don't stop bitcoinds after the test execution")
+ parser.add_option("--srcdir", dest="srcdir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../../src"),
+ help="Source directory containing bitcoind/bitcoin-cli (default: %default)")
+ parser.add_option("--cachedir", dest="cachedir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../cache"),
+ help="Directory for caching pregenerated datadirs")
+ parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
+ help="Root directory for datadirs")
+ parser.add_option("-l", "--loglevel", dest="loglevel", default="INFO",
+ help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console. Note that logs at all levels are always written to the test_framework.log file in the temporary test directory.")
+ parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true",
+ help="Print out all RPC calls as they are made")
+ parser.add_option("--portseed", dest="port_seed", default=os.getpid(), type='int',
+ help="The seed to use for assigning port numbers (default: current process id)")
+ parser.add_option("--coveragedir", dest="coveragedir",
+ help="Write tested RPC commands into this directory")
+ parser.add_option("--configfile", dest="configfile",
+ help="Location of the test framework config file")
+ self.add_options(parser)
+ (self.options, self.args) = parser.parse_args()
+
+ # backup dir variable for removal at cleanup
+ self.options.root, self.options.tmpdir = self.options.tmpdir, self.options.tmpdir + '/' + str(self.options.port_seed)
+
+ if self.options.coveragedir:
+ enable_coverage(self.options.coveragedir)
+
+ PortSeed.n = self.options.port_seed
+
+ os.environ['PATH'] = self.options.srcdir+":"+self.options.srcdir+"/qt:"+os.environ['PATH']
+
+ check_json_precision()
+
+ # Set up temp directory and start logging
+ os.makedirs(self.options.tmpdir, exist_ok=False)
+ self._start_logging()
+
+ success = False
+
+ try:
+ self.setup_chain()
+ self.setup_network()
+ self.run_test()
+ success = True
+ except JSONRPCException as e:
+ self.log.exception("JSONRPC error")
+ except AssertionError as e:
+ self.log.exception("Assertion failed")
+ except KeyError as e:
+ self.log.exception("Key error")
+ except Exception as e:
+ self.log.exception("Unexpected exception caught during testing")
+ except KeyboardInterrupt as e:
+ self.log.warning("Exiting after keyboard interrupt")
+
+ if not self.options.noshutdown:
+ self.log.info("Stopping nodes")
+ self.stop_nodes()
+ else:
+ self.log.info("Note: bitcoinds were not stopped and may still be running")
+
+ if not self.options.nocleanup and not self.options.noshutdown and success:
+ self.log.info("Cleaning up")
+ shutil.rmtree(self.options.tmpdir)
+ if not os.listdir(self.options.root):
+ os.rmdir(self.options.root)
+ else:
+ self.log.warning("Not cleaning up dir %s" % self.options.tmpdir)
+ if os.getenv("PYTHON_DEBUG", ""):
+ # Dump the end of the debug logs, to aid in debugging rare
+ # travis failures.
+ import glob
+ filenames = [self.options.tmpdir + "/test_framework.log"]
+ filenames += glob.glob(self.options.tmpdir + "/node*/regtest/debug.log")
+ MAX_LINES_TO_PRINT = 1000
+ for fn in filenames:
+ try:
+ with open(fn, 'r') as f:
+ print("From" , fn, ":")
+ print("".join(deque(f, MAX_LINES_TO_PRINT)))
+ except OSError:
+ print("Opening file %s failed." % fn)
+ traceback.print_exc()
+ if success:
+ self.log.info("Tests successful")
+ sys.exit(self.TEST_EXIT_PASSED)
+ else:
+ self.log.error("Test failed. Test logging available at %s/test_framework.log", self.options.tmpdir)
+ logging.shutdown()
+ sys.exit(self.TEST_EXIT_FAILED)
+
+ # Public helper methods. These can be accessed by the subclass test scripts.
+
+ def start_node(self, i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None):
+ return start_node(i, dirname, extra_args, rpchost, timewait, binary, stderr)
+
+ def start_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
+ return start_nodes(num_nodes, dirname, extra_args, rpchost, timewait, binary)
+
+ def stop_node(self, num_node):
+ stop_node(self.nodes[num_node], num_node)
+
+ def stop_nodes(self):
+ stop_nodes(self.nodes)
+
+ def split_network(self):
+ """
+ Split the network of four nodes into nodes 0/1 and 2/3.
+ """
+ disconnect_nodes(self.nodes[1], 2)
+ disconnect_nodes(self.nodes[2], 1)
+ self.sync_all([self.nodes[:2], self.nodes[2:]])
+
+ def join_network(self):
+ """
+ Join the (previously split) network halves together.
+ """
+ connect_nodes_bi(self.nodes, 1, 2)
+ self.sync_all()
+
+ def sync_all(self, node_groups=None):
+ if not node_groups:
+ node_groups = [self.nodes]
+
+ for group in node_groups:
+ sync_blocks(group)
+ sync_mempools(group)
+
+ # Private helper methods. These should not be accessed by the subclass test scripts.
+
+ def _start_logging(self):
+ # Add logger and logging handlers
+ self.log = logging.getLogger('TestFramework')
+ self.log.setLevel(logging.DEBUG)
+ # Create file handler to log all messages
+ fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log')
+ fh.setLevel(logging.DEBUG)
+ # Create console handler to log messages to stderr. By default this logs only error messages, but can be configured with --loglevel.
+ ch = logging.StreamHandler(sys.stdout)
+ # User can provide log level as a number or string (eg DEBUG). loglevel was caught as a string, so try to convert it to an int
+ ll = int(self.options.loglevel) if self.options.loglevel.isdigit() else self.options.loglevel.upper()
+ ch.setLevel(ll)
+ # Format logs the same as bitcoind's debug.log with microprecision (so log files can be concatenated and sorted)
+ formatter = logging.Formatter(fmt = '%(asctime)s.%(msecs)03d000 %(name)s (%(levelname)s): %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
+ formatter.converter = time.gmtime
+ fh.setFormatter(formatter)
+ ch.setFormatter(formatter)
+ # add the handlers to the logger
+ self.log.addHandler(fh)
+ self.log.addHandler(ch)
+
+ if self.options.trace_rpc:
+ rpc_logger = logging.getLogger("BitcoinRPC")
+ rpc_logger.setLevel(logging.DEBUG)
+ rpc_handler = logging.StreamHandler(sys.stdout)
+ rpc_handler.setLevel(logging.DEBUG)
+ rpc_logger.addHandler(rpc_handler)
+
+ def _initialize_chain(self, test_dir, num_nodes, cachedir):
+ """Initialize a pre-mined blockchain for use by the test.
+
+ Create a cache of a 200-block-long chain (with wallet) for MAX_NODES
+ Afterward, create num_nodes copies from the cache."""
+
+ assert num_nodes <= MAX_NODES
+ create_cache = False
+ for i in range(MAX_NODES):
+ if not os.path.isdir(os.path.join(cachedir, 'node' + str(i))):
+ create_cache = True
+ break
+
+ if create_cache:
+ self.log.debug("Creating data directories from cached datadir")
+
+ # find and delete old cache directories if any exist
+ for i in range(MAX_NODES):
+ if os.path.isdir(os.path.join(cachedir, "node" + str(i))):
+ shutil.rmtree(os.path.join(cachedir, "node" + str(i)))
+
+ # Create cache directories, run bitcoinds:
+ for i in range(MAX_NODES):
+ datadir = initialize_datadir(cachedir, i)
+ args = [os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir=" + datadir, "-discover=0"]
+ if i > 0:
+ args.append("-connect=127.0.0.1:" + str(p2p_port(0)))
+ bitcoind_processes[i] = subprocess.Popen(args)
+ self.log.debug("initialize_chain: bitcoind started, waiting for RPC to come up")
+ wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i)
+ self.log.debug("initialize_chain: RPC successfully started")
+
+ self.nodes = []
+ for i in range(MAX_NODES):
+ try:
+ self.nodes.append(get_rpc_proxy(rpc_url(i), i))
+ except:
+ self.log.exception("Error connecting to node %d" % i)
+ sys.exit(1)
+
+ # Create a 200-block-long chain; each of the 4 first nodes
+ # gets 25 mature blocks and 25 immature.
+ # Note: To preserve compatibility with older versions of
+ # initialize_chain, only 4 nodes will generate coins.
+ #
+ # blocks are created with timestamps 10 minutes apart
+ # starting from 2010 minutes in the past
+ enable_mocktime()
+ block_time = get_mocktime() - (201 * 10 * 60)
+ for i in range(2):
+ for peer in range(4):
+ for j in range(25):
+ set_node_times(self.nodes, block_time)
+ self.nodes[peer].generate(1)
+ block_time += 10 * 60
+ # Must sync before next peer starts generating blocks
+ sync_blocks(self.nodes)
+
+ # Shut them down, and clean up cache directories:
+ self.stop_nodes()
+ self.nodes = []
+ disable_mocktime()
+ for i in range(MAX_NODES):
+ os.remove(log_filename(cachedir, i, "debug.log"))
+ os.remove(log_filename(cachedir, i, "db.log"))
+ os.remove(log_filename(cachedir, i, "peers.dat"))
+ os.remove(log_filename(cachedir, i, "fee_estimates.dat"))
+
+ for i in range(num_nodes):
+ from_dir = os.path.join(cachedir, "node" + str(i))
+ to_dir = os.path.join(test_dir, "node" + str(i))
+ shutil.copytree(from_dir, to_dir)
+ initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf
+
+ def _initialize_chain_clean(self, test_dir, num_nodes):
+ """Initialize empty blockchain for use by the test.
+
+ Create an empty blockchain and num_nodes wallets.
+ Useful if a test case wants complete control over initialization."""
+ for i in range(num_nodes):
+ initialize_datadir(test_dir, i)
+
+# Test framework for doing p2p comparison testing, which sets up some bitcoind
+# binaries:
+# 1 binary: test binary
+# 2 binaries: 1 test binary, 1 ref binary
+# n>2 binaries: 1 test binary, n-1 ref binaries
+
+class ComparisonTestFramework(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = True
+
+ def add_options(self, parser):
+ parser.add_option("--testbinary", dest="testbinary",
+ default=os.getenv("BITCOIND", "bitcoind"),
+ help="bitcoind binary to test")
+ parser.add_option("--refbinary", dest="refbinary",
+ default=os.getenv("BITCOIND", "bitcoind"),
+ help="bitcoind binary to use for reference nodes (if any)")
+
+ def setup_network(self):
+ self.nodes = self.start_nodes(
+ self.num_nodes, self.options.tmpdir,
+ extra_args=[['-whitelist=127.0.0.1']] * self.num_nodes,
+ binary=[self.options.testbinary] +
+ [self.options.refbinary]*(self.num_nodes-1))
diff --git a/qa/rpc-tests/test_framework/util.py b/test/functional/test_framework/util.py
index 32fe79efc3..2b56fe8d62 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -2,11 +2,7 @@
# Copyright (c) 2014-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.
-
-
-#
-# Helpful routines for regression testing
-#
+"""Helpful routines for regression testing."""
import os
import sys
@@ -19,15 +15,19 @@ import http.client
import random
import shutil
import subprocess
+import tempfile
import time
import re
import errno
+import logging
from . import coverage
from .authproxy import AuthServiceProxy, JSONRPCException
COVERAGE_DIR = None
+logger = logging.getLogger("TestFramework.utils")
+
# The maximum number of nodes a single test can spawn
MAX_NODES = 8
# Don't assign rpc or p2p ports lower than this
@@ -121,19 +121,44 @@ def hex_str_to_bytes(hex_str):
def str_to_b64str(string):
return b64encode(string.encode('utf-8')).decode('ascii')
-def sync_blocks(rpc_connections, wait=1, timeout=60):
+def sync_blocks(rpc_connections, *, wait=1, timeout=60):
+ """
+ Wait until everybody has the same tip.
+
+ sync_blocks needs to be called with an rpc_connections set that has least
+ one node already synced to the latest, stable tip, otherwise there's a
+ chance it might return before all nodes are stably synced.
+ """
+ # Use getblockcount() instead of waitforblockheight() to determine the
+ # initial max height because the two RPCs look at different internal global
+ # variables (chainActive vs latestBlock) and the former gets updated
+ # earlier.
+ maxheight = max(x.getblockcount() for x in rpc_connections)
+ start_time = cur_time = time.time()
+ while cur_time <= start_time + timeout:
+ tips = [r.waitforblockheight(maxheight, int(wait * 1000)) for r in rpc_connections]
+ if all(t["height"] == maxheight for t in tips):
+ if all(t["hash"] == tips[0]["hash"] for t in tips):
+ return
+ raise AssertionError("Block sync failed, mismatched block hashes:{}".format(
+ "".join("\n {!r}".format(tip) for tip in tips)))
+ cur_time = time.time()
+ raise AssertionError("Block sync to height {} timed out:{}".format(
+ maxheight, "".join("\n {!r}".format(tip) for tip in tips)))
+
+def sync_chain(rpc_connections, *, wait=1, timeout=60):
"""
- Wait until everybody has the same tip
+ Wait until everybody has the same best block
"""
while timeout > 0:
- tips = [ x.getbestblockhash() for x in rpc_connections ]
- if tips == [ tips[0] ]*len(tips):
- return True
+ best_hash = [x.getbestblockhash() for x in rpc_connections]
+ if best_hash == [best_hash[0]]*len(best_hash):
+ return
time.sleep(wait)
timeout -= wait
- raise AssertionError("Block sync failed")
+ raise AssertionError("Chain sync failed: Best block hashes don't match")
-def sync_mempools(rpc_connections, wait=1, timeout=60):
+def sync_mempools(rpc_connections, *, wait=1, timeout=60):
"""
Wait until everybody has the same transactions in their memory
pools
@@ -145,7 +170,7 @@ def sync_mempools(rpc_connections, wait=1, timeout=60):
if set(rpc_connections[i].getrawmempool()) == pool:
num_match = num_match+1
if num_match == len(rpc_connections):
- return True
+ return
time.sleep(wait)
timeout -= wait
raise AssertionError("Mempool sync failed")
@@ -157,7 +182,7 @@ def initialize_datadir(dirname, n):
if not os.path.isdir(datadir):
os.makedirs(datadir)
rpc_u, rpc_p = rpc_auth_pair(n)
- with open(os.path.join(datadir, "bitcoin.conf"), 'w') as f:
+ with open(os.path.join(datadir, "bitcoin.conf"), 'w', encoding='utf8') as f:
f.write("regtest=1\n")
f.write("rpcuser=" + rpc_u + "\n")
f.write("rpcpassword=" + rpc_p + "\n")
@@ -171,7 +196,15 @@ def rpc_auth_pair(n):
def rpc_url(i, rpchost=None):
rpc_u, rpc_p = rpc_auth_pair(i)
- return "http://%s:%s@%s:%d" % (rpc_u, rpc_p, rpchost or '127.0.0.1', rpc_port(i))
+ host = '127.0.0.1'
+ port = rpc_port(i)
+ if rpchost:
+ parts = rpchost.split(':')
+ if len(parts) == 2:
+ host, port = parts
+ else:
+ host = rpchost
+ return "http://%s:%s@%s:%d" % (rpc_u, rpc_p, host, int(port))
def wait_for_bitcoind_start(process, url, i):
'''
@@ -190,129 +223,24 @@ def wait_for_bitcoind_start(process, url, i):
raise # unknown IO error
except JSONRPCException as e: # Initialization phase
if e.error['code'] != -28: # RPC in warmup?
- raise # unkown JSON RPC exception
+ raise # unknown JSON RPC exception
time.sleep(0.25)
-def initialize_chain(test_dir, num_nodes):
- """
- Create a cache of a 200-block-long chain (with wallet) for MAX_NODES
- Afterward, create num_nodes copies from the cache
- """
-
- assert num_nodes <= MAX_NODES
- create_cache = False
- for i in range(MAX_NODES):
- if not os.path.isdir(os.path.join('cache', 'node'+str(i))):
- create_cache = True
- break
- if create_cache:
-
- #find and delete old cache directories if any exist
- for i in range(MAX_NODES):
- if os.path.isdir(os.path.join("cache","node"+str(i))):
- shutil.rmtree(os.path.join("cache","node"+str(i)))
-
- # Create cache directories, run bitcoinds:
- for i in range(MAX_NODES):
- datadir=initialize_datadir("cache", i)
- args = [ os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir="+datadir, "-discover=0" ]
- if i > 0:
- args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
- bitcoind_processes[i] = subprocess.Popen(args)
- if os.getenv("PYTHON_DEBUG", ""):
- print("initialize_chain: bitcoind started, waiting for RPC to come up")
- wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i)
- if os.getenv("PYTHON_DEBUG", ""):
- print("initialize_chain: RPC succesfully started")
-
- rpcs = []
- for i in range(MAX_NODES):
- try:
- rpcs.append(get_rpc_proxy(rpc_url(i), i))
- except:
- sys.stderr.write("Error connecting to "+url+"\n")
- sys.exit(1)
-
- # Create a 200-block-long chain; each of the 4 first nodes
- # gets 25 mature blocks and 25 immature.
- # Note: To preserve compatibility with older versions of
- # initialize_chain, only 4 nodes will generate coins.
- #
- # blocks are created with timestamps 10 minutes apart
- # starting from 2010 minutes in the past
- enable_mocktime()
- block_time = get_mocktime() - (201 * 10 * 60)
- for i in range(2):
- for peer in range(4):
- for j in range(25):
- set_node_times(rpcs, block_time)
- rpcs[peer].generate(1)
- block_time += 10*60
- # Must sync before next peer starts generating blocks
- sync_blocks(rpcs)
-
- # Shut them down, and clean up cache directories:
- stop_nodes(rpcs)
- wait_bitcoinds()
- disable_mocktime()
- for i in range(MAX_NODES):
- os.remove(log_filename("cache", i, "debug.log"))
- os.remove(log_filename("cache", i, "db.log"))
- os.remove(log_filename("cache", i, "peers.dat"))
- os.remove(log_filename("cache", i, "fee_estimates.dat"))
-
- for i in range(num_nodes):
- from_dir = os.path.join("cache", "node"+str(i))
- to_dir = os.path.join(test_dir, "node"+str(i))
- shutil.copytree(from_dir, to_dir)
- initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf
-
-def initialize_chain_clean(test_dir, num_nodes):
- """
- Create an empty blockchain and num_nodes wallets.
- Useful if a test case wants complete control over initialization.
- """
- for i in range(num_nodes):
- datadir=initialize_datadir(test_dir, i)
-
-
-def _rpchost_to_args(rpchost):
- '''Convert optional IP:port spec to rpcconnect/rpcport args'''
- if rpchost is None:
- return []
-
- match = re.match('(\[[0-9a-fA-f:]+\]|[^:]+)(?::([0-9]+))?$', rpchost)
- if not match:
- raise ValueError('Invalid RPC host spec ' + rpchost)
-
- rpcconnect = match.group(1)
- rpcport = match.group(2)
-
- if rpcconnect.startswith('['): # remove IPv6 [...] wrapping
- rpcconnect = rpcconnect[1:-1]
-
- rv = ['-rpcconnect=' + rpcconnect]
- if rpcport:
- rv += ['-rpcport=' + rpcport]
- return rv
-
-def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
+def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None):
"""
Start a bitcoind and return RPC connection to it
"""
datadir = os.path.join(dirname, "node"+str(i))
if binary is None:
binary = os.getenv("BITCOIND", "bitcoind")
- args = [ binary, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-mocktime="+str(get_mocktime()) ]
+ args = [binary, "-datadir=" + datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(get_mocktime()), "-uacomment=testnode%d" % i]
if extra_args is not None: args.extend(extra_args)
- bitcoind_processes[i] = subprocess.Popen(args)
- if os.getenv("PYTHON_DEBUG", ""):
- print("start_node: bitcoind started, waiting for RPC to come up")
+ bitcoind_processes[i] = subprocess.Popen(args, stderr=stderr)
+ logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up")
url = rpc_url(i, rpchost)
wait_for_bitcoind_start(bitcoind_processes[i], url, i)
- if os.getenv("PYTHON_DEBUG", ""):
- print("start_node: RPC succesfully started")
+ logger.debug("initialize_chain: RPC successfully started")
proxy = get_rpc_proxy(url, i, timeout=timewait)
if COVERAGE_DIR:
@@ -320,16 +248,37 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=
return proxy
-def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None):
+def assert_start_raises_init_error(i, dirname, extra_args=None, expected_msg=None):
+ with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr:
+ try:
+ node = start_node(i, dirname, extra_args, stderr=log_stderr)
+ stop_node(node, i)
+ except Exception as e:
+ assert 'bitcoind exited' in str(e) #node must have shutdown
+ if expected_msg is not None:
+ log_stderr.seek(0)
+ stderr = log_stderr.read().decode('utf-8')
+ if expected_msg not in stderr:
+ raise AssertionError("Expected error \"" + expected_msg + "\" not found in:\n" + stderr)
+ else:
+ if expected_msg is None:
+ assert_msg = "bitcoind should have exited with an error"
+ else:
+ assert_msg = "bitcoind should have exited with expected error " + expected_msg
+ raise AssertionError(assert_msg)
+
+def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
"""
Start multiple bitcoinds, return RPC connections to them
"""
if extra_args is None: extra_args = [ None for _ in range(num_nodes) ]
if binary is None: binary = [ None for _ in range(num_nodes) ]
+ assert_equal(len(extra_args), num_nodes)
+ assert_equal(len(binary), num_nodes)
rpcs = []
try:
for i in range(num_nodes):
- rpcs.append(start_node(i, dirname, extra_args[i], rpchost, binary=binary[i]))
+ rpcs.append(start_node(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i]))
except: # If one node failed to start, stop the others
stop_nodes(rpcs)
raise
@@ -339,30 +288,34 @@ def log_filename(dirname, n_node, logname):
return os.path.join(dirname, "node"+str(n_node), "regtest", logname)
def stop_node(node, i):
+ logger.debug("Stopping node %d" % i)
try:
node.stop()
except http.client.CannotSendRequest as e:
- print("WARN: Unable to stop node: " + repr(e))
- bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
+ logger.exception("Unable to stop node")
+ return_code = bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
+ assert_equal(return_code, 0)
del bitcoind_processes[i]
def stop_nodes(nodes):
- for node in nodes:
- try:
- node.stop()
- except http.client.CannotSendRequest as e:
- print("WARN: Unable to stop node: " + repr(e))
- del nodes[:] # Emptying array closes connections as a side effect
+ for i, node in enumerate(nodes):
+ stop_node(node, i)
+ assert not bitcoind_processes.values() # All connections must be gone now
def set_node_times(nodes, t):
for node in nodes:
node.setmocktime(t)
-def wait_bitcoinds():
- # Wait for all bitcoinds to cleanly exit
- for bitcoind in bitcoind_processes.values():
- bitcoind.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
- bitcoind_processes.clear()
+def disconnect_nodes(from_connection, node_num):
+ for peer_id in [peer['id'] for peer in from_connection.getpeerinfo() if "testnode%d" % node_num in peer['subver']]:
+ from_connection.disconnectnode(nodeid=peer_id)
+
+ for _ in range(50):
+ if [peer['id'] for peer in from_connection.getpeerinfo() if "testnode%d" % node_num in peer['subver']] == []:
+ break
+ time.sleep(0.1)
+ else:
+ raise AssertionError("timed out waiting for disconnect")
def connect_nodes(from_connection, node_num):
ip_port = "127.0.0.1:"+str(p2p_port(node_num))
@@ -422,47 +375,6 @@ def make_change(from_node, amount_in, amount_out, fee):
outputs[from_node.getnewaddress()] = change
return outputs
-def send_zeropri_transaction(from_node, to_node, amount, fee):
- """
- Create&broadcast a zero-priority transaction.
- Returns (txid, hex-encoded-txdata)
- Ensures transaction is zero-priority by first creating a send-to-self,
- then using its output
- """
-
- # Create a send-to-self with confirmed inputs:
- self_address = from_node.getnewaddress()
- (total_in, inputs) = gather_inputs(from_node, amount+fee*2)
- outputs = make_change(from_node, total_in, amount+fee, fee)
- outputs[self_address] = float(amount+fee)
-
- self_rawtx = from_node.createrawtransaction(inputs, outputs)
- self_signresult = from_node.signrawtransaction(self_rawtx)
- self_txid = from_node.sendrawtransaction(self_signresult["hex"], True)
-
- vout = find_output(from_node, self_txid, amount+fee)
- # Now immediately spend the output to create a 1-input, 1-output
- # zero-priority transaction:
- inputs = [ { "txid" : self_txid, "vout" : vout } ]
- outputs = { to_node.getnewaddress() : float(amount) }
-
- rawtx = from_node.createrawtransaction(inputs, outputs)
- signresult = from_node.signrawtransaction(rawtx)
- txid = from_node.sendrawtransaction(signresult["hex"], True)
-
- return (txid, signresult["hex"])
-
-def random_zeropri_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
- """
- Create a random zero-priority transaction.
- Returns (txid, hex-encoded-transaction-data, fee)
- """
- from_node = random.choice(nodes)
- to_node = random.choice(nodes)
- fee = min_fee + fee_increment*random.randint(0,fee_variants)
- (txid, txhex) = send_zeropri_transaction(from_node, to_node, amount, fee)
- return (txid, txhex, fee)
-
def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
"""
Create a random transaction.
@@ -491,19 +403,56 @@ def assert_fee_amount(fee, tx_size, fee_per_kB):
if fee > (tx_size + 2) * fee_per_kB / 1000:
raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)"%(str(fee), str(target_fee)))
-def assert_equal(thing1, thing2):
- if thing1 != thing2:
- raise AssertionError("%s != %s"%(str(thing1),str(thing2)))
+def assert_equal(thing1, thing2, *args):
+ if thing1 != thing2 or any(thing1 != arg for arg in args):
+ raise AssertionError("not(%s)" % " == ".join(str(arg) for arg in (thing1, thing2) + args))
def assert_greater_than(thing1, thing2):
if thing1 <= thing2:
raise AssertionError("%s <= %s"%(str(thing1),str(thing2)))
+def assert_greater_than_or_equal(thing1, thing2):
+ if thing1 < thing2:
+ raise AssertionError("%s < %s"%(str(thing1),str(thing2)))
+
def assert_raises(exc, fun, *args, **kwds):
+ assert_raises_message(exc, None, fun, *args, **kwds)
+
+def assert_raises_message(exc, message, fun, *args, **kwds):
try:
fun(*args, **kwds)
- except exc:
- pass
+ except exc as e:
+ if message is not None and message not in e.error['message']:
+ raise AssertionError("Expected substring not found:"+e.error['message'])
+ except Exception as e:
+ raise AssertionError("Unexpected exception raised: "+type(e).__name__)
+ else:
+ raise AssertionError("No exception raised")
+
+def assert_raises_jsonrpc(code, message, fun, *args, **kwds):
+ """Run an RPC and verify that a specific JSONRPC exception code and message is raised.
+
+ Calls function `fun` with arguments `args` and `kwds`. Catches a JSONRPCException
+ and verifies that the error code and message are as expected. Throws AssertionError if
+ no JSONRPCException was returned or if the error code/message are not as expected.
+
+ Args:
+ code (int), optional: the error code returned by the RPC call (defined
+ in src/rpc/protocol.h). Set to None if checking the error code is not required.
+ message (string), optional: [a substring of] the error string returned by the
+ RPC call. Set to None if checking the error string is not required
+ fun (function): the function to call. This should be the name of an RPC.
+ args*: positional arguments for the function.
+ kwds**: named arguments for the function.
+ """
+ try:
+ fun(*args, **kwds)
+ except JSONRPCException as e:
+ # JSONRPCException was thrown as expected. Check the code and message values are correct.
+ if (code is not None) and (code != e.error["code"]):
+ raise AssertionError("Unexpected JSONRPC error code %i" % e.error["code"])
+ if (message is not None) and (message not in e.error['message']):
+ raise AssertionError("Expected substring not found:"+e.error['message'])
except Exception as e:
raise AssertionError("Unexpected exception raised: "+type(e).__name__)
else:
@@ -617,16 +566,15 @@ def create_tx(node, coinbase, to_address, amount):
# Create a spend of each passed-in utxo, splicing in "txouts" to each raw
# transaction to make it large. See gen_return_txouts() above.
-def create_lots_of_big_transactions(node, txouts, utxos, fee):
+def create_lots_of_big_transactions(node, txouts, utxos, num, fee):
addr = node.getnewaddress()
txids = []
- for i in range(len(utxos)):
+ for _ in range(num):
t = utxos.pop()
- inputs = []
- inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
+ inputs=[{ "txid" : t["txid"], "vout" : t["vout"]}]
outputs = {}
- send_value = t['amount'] - fee
- outputs[addr] = satoshi_round(send_value)
+ change = t['amount'] - fee
+ outputs[addr] = satoshi_round(change)
rawtx = node.createrawtransaction(inputs, outputs)
newtx = rawtx[0:92]
newtx = newtx + txouts
@@ -636,6 +584,19 @@ def create_lots_of_big_transactions(node, txouts, utxos, fee):
txids.append(txid)
return txids
+def mine_large_block(node, utxos=None):
+ # generate a 66k transaction,
+ # and 14 of them is close to the 1MB block limit
+ num = 14
+ txouts = gen_return_txouts()
+ utxos = utxos if utxos is not None else []
+ if len(utxos) < num:
+ utxos.clear()
+ utxos.extend(node.listunspent())
+ fee = 100 * node.getnetworkinfo()["relayfee"]
+ create_lots_of_big_transactions(node, txouts, utxos, num, fee=fee)
+ node.generate(1)
+
def get_bip9_status(node, key):
info = node.getblockchaininfo()
return info['bip9_softforks'][key]
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
new file mode 100755
index 0000000000..6174ca1d88
--- /dev/null
+++ b/test/functional/test_runner.py
@@ -0,0 +1,500 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+"""Run regression test suite.
+
+This module calls down into individual test cases via subprocess. It will
+forward all unrecognized arguments onto the individual test scripts.
+
+Functional tests are disabled on Windows by default. Use --force to run them anyway.
+
+For a description of arguments recognized by test scripts, see
+`test/functional/test_framework/test_framework.py:BitcoinTestFramework.main`.
+
+"""
+
+import argparse
+import configparser
+import os
+import time
+import shutil
+import sys
+import subprocess
+import tempfile
+import re
+import logging
+
+# Formatting. Default colors to empty strings.
+BOLD, BLUE, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "")
+try:
+ # Make sure python thinks it can write unicode to its stdout
+ "\u2713".encode("utf_8").decode(sys.stdout.encoding)
+ TICK = "✓ "
+ CROSS = "✖ "
+ CIRCLE = "○ "
+except UnicodeDecodeError:
+ TICK = "P "
+ CROSS = "x "
+ CIRCLE = "o "
+
+if os.name == 'posix':
+ # primitive formatting on supported
+ # terminal via ANSI escape sequences:
+ BOLD = ('\033[0m', '\033[1m')
+ BLUE = ('\033[0m', '\033[0;34m')
+ RED = ('\033[0m', '\033[0;31m')
+ GREY = ('\033[0m', '\033[1;30m')
+
+TEST_EXIT_PASSED = 0
+TEST_EXIT_SKIPPED = 77
+
+BASE_SCRIPTS= [
+ # Scripts that are run by the travis build process.
+ # Longest test should go first, to favor running tests in parallel
+ 'wallet-hd.py',
+ 'walletbackup.py',
+ # vv Tests less than 5m vv
+ 'p2p-fullblocktest.py',
+ 'fundrawtransaction.py',
+ 'p2p-compactblocks.py',
+ 'segwit.py',
+ # vv Tests less than 2m vv
+ 'wallet.py',
+ 'wallet-accounts.py',
+ 'p2p-segwit.py',
+ 'wallet-dump.py',
+ 'listtransactions.py',
+ # vv Tests less than 60s vv
+ 'sendheaders.py',
+ 'zapwallettxes.py',
+ 'importmulti.py',
+ 'mempool_limit.py',
+ 'merkle_blocks.py',
+ 'receivedby.py',
+ 'abandonconflict.py',
+ 'bip68-112-113-p2p.py',
+ 'rawtransactions.py',
+ 'reindex.py',
+ # vv Tests less than 30s vv
+ "zmq_test.py",
+ 'mempool_resurrect_test.py',
+ 'txn_doublespend.py --mineblock',
+ 'txn_clone.py',
+ 'getchaintips.py',
+ 'rest.py',
+ 'mempool_spendcoinbase.py',
+ 'mempool_reorg.py',
+ 'mempool_persist.py',
+ 'httpbasics.py',
+ 'multi_rpc.py',
+ 'proxy_test.py',
+ 'signrawtransactions.py',
+ 'disconnect_ban.py',
+ 'decodescript.py',
+ 'blockchain.py',
+ 'disablewallet.py',
+ 'net.py',
+ 'keypool.py',
+ 'p2p-mempool.py',
+ 'prioritise_transaction.py',
+ 'invalidblockrequest.py',
+ 'invalidtxrequest.py',
+ 'p2p-versionbits-warning.py',
+ 'preciousblock.py',
+ 'importprunedfunds.py',
+ 'signmessages.py',
+ 'nulldummy.py',
+ 'import-rescan.py',
+ 'bumpfee.py',
+ 'rpcnamedargs.py',
+ 'listsinceblock.py',
+ 'p2p-leaktests.py',
+]
+
+EXTENDED_SCRIPTS = [
+ # These tests are not run by the travis build process.
+ # Longest test should go first, to favor running tests in parallel
+ 'pruning.py',
+ # vv Tests less than 20m vv
+ 'smartfees.py',
+ # vv Tests less than 5m vv
+ 'maxuploadtarget.py',
+ 'mempool_packages.py',
+ # vv Tests less than 2m vv
+ 'bip68-sequence.py',
+ 'getblocktemplate_longpoll.py',
+ 'p2p-timeouts.py',
+ # vv Tests less than 60s vv
+ 'bip9-softforks.py',
+ 'p2p-feefilter.py',
+ 'rpcbind_test.py',
+ # vv Tests less than 30s vv
+ 'assumevalid.py',
+ 'bip65-cltv.py',
+ 'bip65-cltv-p2p.py',
+ 'bipdersig-p2p.py',
+ 'bipdersig.py',
+ 'getblocktemplate_proposals.py',
+ 'txn_doublespend.py',
+ 'txn_clone.py --mineblock',
+ 'forknotify.py',
+ 'invalidateblock.py',
+ 'p2p-acceptblock.py',
+ 'replace-by-fee.py',
+]
+
+# Place EXTENDED_SCRIPTS first since it has the 3 longest running tests
+ALL_SCRIPTS = EXTENDED_SCRIPTS + BASE_SCRIPTS
+
+NON_SCRIPTS = [
+ # These are python files that live in the functional tests directory, but are not test scripts.
+ "combine_logs.py",
+ "create_cache.py",
+ "test_runner.py",
+]
+
+def main():
+ # Parse arguments and pass through unrecognised args
+ parser = argparse.ArgumentParser(add_help=False,
+ usage='%(prog)s [test_runner.py options] [script options] [scripts]',
+ description=__doc__,
+ epilog='''
+ Help text and arguments for individual test script:''',
+ formatter_class=argparse.RawTextHelpFormatter)
+ parser.add_argument('--coverage', action='store_true', help='generate a basic coverage report for the RPC interface')
+ parser.add_argument('--exclude', '-x', help='specify a comma-seperated-list of scripts to exclude.')
+ parser.add_argument('--extended', action='store_true', help='run the extended test suite in addition to the basic tests')
+ parser.add_argument('--force', '-f', action='store_true', help='run tests even on platforms where they are disabled by default (e.g. windows).')
+ parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit')
+ parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.')
+ parser.add_argument('--keepcache', '-k', action='store_true', help='the default behavior is to flush the cache directory on startup. --keepcache retains the cache from the previous testrun.')
+ parser.add_argument('--quiet', '-q', action='store_true', help='only print results summary and failure logs')
+ args, unknown_args = parser.parse_known_args()
+
+ # args to be passed on always start with two dashes; tests are the remaining unknown args
+ tests = [arg for arg in unknown_args if arg[:2] != "--"]
+ passon_args = [arg for arg in unknown_args if arg[:2] == "--"]
+
+ # Read config generated by configure.
+ config = configparser.ConfigParser()
+ configfile = os.path.abspath(os.path.dirname(__file__)) + "/config.ini"
+ config.read_file(open(configfile))
+
+ passon_args.append("--configfile=%s" % configfile)
+
+ # Set up logging
+ logging_level = logging.INFO if args.quiet else logging.DEBUG
+ logging.basicConfig(format='%(message)s', level=logging_level)
+
+ enable_wallet = config["components"].getboolean("ENABLE_WALLET")
+ enable_utils = config["components"].getboolean("ENABLE_UTILS")
+ enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND")
+
+ if config["environment"]["EXEEXT"] == ".exe" and not args.force:
+ # https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
+ # https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
+ print("Tests currently disabled on Windows by default. Use --force option to enable")
+ sys.exit(0)
+
+ if not (enable_wallet and enable_utils and enable_bitcoind):
+ print("No functional tests to run. Wallet, utils, and bitcoind must all be enabled")
+ print("Rerun `configure` with -enable-wallet, -with-utils and -with-daemon and rerun make")
+ sys.exit(0)
+
+ # Build list of tests
+ if tests:
+ # Individual tests have been specified. Run specified tests that exist
+ # in the ALL_SCRIPTS list. Accept the name with or without .py extension.
+ tests = [re.sub("\.py$", "", t) + ".py" for t in tests]
+ test_list = []
+ for t in tests:
+ if t in ALL_SCRIPTS:
+ test_list.append(t)
+ else:
+ print("{}WARNING!{} Test '{}' not found in full test list.".format(BOLD[1], BOLD[0], t))
+ else:
+ # No individual tests have been specified.
+ # Run all base tests, and optionally run extended tests.
+ test_list = BASE_SCRIPTS
+ if args.extended:
+ # place the EXTENDED_SCRIPTS first since the three longest ones
+ # are there and the list is shorter
+ test_list = EXTENDED_SCRIPTS + test_list
+
+ # Remove the test cases that the user has explicitly asked to exclude.
+ if args.exclude:
+ tests_excl = [re.sub("\.py$", "", t) + ".py" for t in args.exclude.split(',')]
+ for exclude_test in tests_excl:
+ if exclude_test in test_list:
+ test_list.remove(exclude_test)
+ else:
+ print("{}WARNING!{} Test '{}' not found in current test list.".format(BOLD[1], BOLD[0], exclude_test))
+
+ if not test_list:
+ print("No valid test scripts specified. Check that your test is in one "
+ "of the test lists in test_runner.py, or run test_runner.py with no arguments to run all tests")
+ sys.exit(0)
+
+ if args.help:
+ # Print help for test_runner.py, then print help of the first script (with args removed) and exit.
+ parser.print_help()
+ subprocess.check_call([(config["environment"]["SRCDIR"] + '/test/functional/' + test_list[0].split()[0])] + ['-h'])
+ sys.exit(0)
+
+ check_script_list(config["environment"]["SRCDIR"])
+
+ if not args.keepcache:
+ shutil.rmtree("%s/test/cache" % config["environment"]["BUILDDIR"], ignore_errors=True)
+
+ run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], args.jobs, args.coverage, passon_args)
+
+def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=False, args=[]):
+ # Warn if bitcoind is already running (unix only)
+ try:
+ if subprocess.check_output(["pidof", "bitcoind"]) is not None:
+ print("%sWARNING!%s There is already a bitcoind process running on this system. Tests may fail unexpectedly due to resource contention!" % (BOLD[1], BOLD[0]))
+ except (OSError, subprocess.SubprocessError):
+ pass
+
+ # Warn if there is a cache directory
+ cache_dir = "%s/test/cache" % build_dir
+ if os.path.isdir(cache_dir):
+ print("%sWARNING!%s There is a cache directory here: %s. If tests fail unexpectedly, try deleting the cache directory." % (BOLD[1], BOLD[0], cache_dir))
+
+ #Set env vars
+ if "BITCOIND" not in os.environ:
+ os.environ["BITCOIND"] = build_dir + '/src/bitcoind' + exeext
+
+ tests_dir = src_dir + '/test/functional/'
+
+ flags = ["--srcdir={}/src".format(build_dir)] + args
+ flags.append("--cachedir=%s" % cache_dir)
+
+ if enable_coverage:
+ coverage = RPCCoverage()
+ flags.append(coverage.flag)
+ logging.debug("Initializing coverage directory at %s" % coverage.dir)
+ else:
+ coverage = None
+
+ if len(test_list) > 1 and jobs > 1:
+ # Populate cache
+ subprocess.check_output([tests_dir + 'create_cache.py'] + flags)
+
+ #Run Tests
+ job_queue = TestHandler(jobs, tests_dir, test_list, flags)
+ time0 = time.time()
+ test_results = []
+
+ max_len_name = len(max(test_list, key=len))
+
+ for _ in range(len(test_list)):
+ test_result, stdout, stderr = job_queue.get_next()
+ test_results.append(test_result)
+
+ if test_result.status == "Passed":
+ logging.debug("\n%s%s%s passed, Duration: %s s" % (BOLD[1], test_result.name, BOLD[0], test_result.time))
+ elif test_result.status == "Skipped":
+ logging.debug("\n%s%s%s skipped" % (BOLD[1], test_result.name, BOLD[0]))
+ else:
+ print("\n%s%s%s failed, Duration: %s s\n" % (BOLD[1], test_result.name, BOLD[0], test_result.time))
+ print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n')
+ print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n')
+
+ print_results(test_results, max_len_name, (int(time.time() - time0)))
+
+ if coverage:
+ coverage.report_rpc_coverage()
+
+ logging.debug("Cleaning up coverage data")
+ coverage.cleanup()
+
+ all_passed = all(map(lambda test_result: test_result.was_successful, test_results))
+
+ sys.exit(not all_passed)
+
+def print_results(test_results, max_len_name, runtime):
+ results = "\n" + BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "STATUS ", "DURATION") + BOLD[0]
+
+ test_results.sort(key=lambda result: result.name.lower())
+ all_passed = True
+ time_sum = 0
+
+ for test_result in test_results:
+ all_passed = all_passed and test_result.was_successful
+ time_sum += test_result.time
+ test_result.padding = max_len_name
+ results += str(test_result)
+
+ status = TICK + "Passed" if all_passed else CROSS + "Failed"
+ results += BOLD[1] + "\n%s | %s | %s s (accumulated) \n" % ("ALL".ljust(max_len_name), status.ljust(9), time_sum) + BOLD[0]
+ results += "Runtime: %s s\n" % (runtime)
+ print(results)
+
+class TestHandler:
+ """
+ Trigger the testscrips passed in via the list.
+ """
+
+ def __init__(self, num_tests_parallel, tests_dir, test_list=None, flags=None):
+ assert(num_tests_parallel >= 1)
+ self.num_jobs = num_tests_parallel
+ self.tests_dir = tests_dir
+ self.test_list = test_list
+ self.flags = flags
+ self.num_running = 0
+ # In case there is a graveyard of zombie bitcoinds, we can apply a
+ # pseudorandom offset to hopefully jump over them.
+ # (625 is PORT_RANGE/MAX_NODES)
+ self.portseed_offset = int(time.time() * 1000) % 625
+ self.jobs = []
+
+ def get_next(self):
+ while self.num_running < self.num_jobs and self.test_list:
+ # Add tests
+ self.num_running += 1
+ t = self.test_list.pop(0)
+ port_seed = ["--portseed={}".format(len(self.test_list) + self.portseed_offset)]
+ log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16)
+ log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
+ test_argv = t.split()
+ self.jobs.append((t,
+ time.time(),
+ subprocess.Popen([self.tests_dir + test_argv[0]] + test_argv[1:] + self.flags + port_seed,
+ universal_newlines=True,
+ stdout=log_stdout,
+ stderr=log_stderr),
+ log_stdout,
+ log_stderr))
+ if not self.jobs:
+ raise IndexError('pop from empty list')
+ while True:
+ # Return first proc that finishes
+ time.sleep(.5)
+ for j in self.jobs:
+ (name, time0, proc, log_out, log_err) = j
+ if proc.poll() is not None:
+ log_out.seek(0), log_err.seek(0)
+ [stdout, stderr] = [l.read().decode('utf-8') for l in (log_out, log_err)]
+ log_out.close(), log_err.close()
+ if proc.returncode == TEST_EXIT_PASSED and stderr == "":
+ status = "Passed"
+ elif proc.returncode == TEST_EXIT_SKIPPED:
+ status = "Skipped"
+ else:
+ status = "Failed"
+ self.num_running -= 1
+ self.jobs.remove(j)
+
+ return TestResult(name, status, int(time.time() - time0)), stdout, stderr
+ print('.', end='', flush=True)
+
+class TestResult():
+ def __init__(self, name, status, time):
+ self.name = name
+ self.status = status
+ self.time = time
+ self.padding = 0
+
+ def __repr__(self):
+ if self.status == "Passed":
+ color = BLUE
+ glyph = TICK
+ elif self.status == "Failed":
+ color = RED
+ glyph = CROSS
+ elif self.status == "Skipped":
+ color = GREY
+ glyph = CIRCLE
+
+ return color[1] + "%s | %s%s | %s s\n" % (self.name.ljust(self.padding), glyph, self.status.ljust(7), self.time) + color[0]
+
+ @property
+ def was_successful(self):
+ return self.status != "Failed"
+
+
+def check_script_list(src_dir):
+ """Check scripts directory.
+
+ Check that there are no scripts in the functional tests directory which are
+ not being run by pull-tester.py."""
+ script_dir = src_dir + '/test/functional/'
+ python_files = set([t for t in os.listdir(script_dir) if t[-3:] == ".py"])
+ missed_tests = list(python_files - set(map(lambda x: x.split()[0], ALL_SCRIPTS + NON_SCRIPTS)))
+ if len(missed_tests) != 0:
+ print("%sWARNING!%s The following scripts are not being run: %s. Check the test lists in test_runner.py." % (BOLD[1], BOLD[0], str(missed_tests)))
+ if os.getenv('TRAVIS') == 'true':
+ # On travis this warning is an error to prevent merging incomplete commits into master
+ sys.exit(1)
+
+class RPCCoverage(object):
+ """
+ Coverage reporting utilities for test_runner.
+
+ Coverage calculation works by having each test script subprocess write
+ coverage files into a particular directory. These files contain the RPC
+ commands invoked during testing, as well as a complete listing of RPC
+ commands per `bitcoin-cli help` (`rpc_interface.txt`).
+
+ After all tests complete, the commands run are combined and diff'd against
+ the complete list to calculate uncovered RPC commands.
+
+ See also: test/functional/test_framework/coverage.py
+
+ """
+ def __init__(self):
+ self.dir = tempfile.mkdtemp(prefix="coverage")
+ self.flag = '--coveragedir=%s' % self.dir
+
+ def report_rpc_coverage(self):
+ """
+ Print out RPC commands that were unexercised by tests.
+
+ """
+ uncovered = self._get_uncovered_rpc_commands()
+
+ if uncovered:
+ print("Uncovered RPC commands:")
+ print("".join((" - %s\n" % i) for i in sorted(uncovered)))
+ else:
+ print("All RPC commands covered.")
+
+ def cleanup(self):
+ return shutil.rmtree(self.dir)
+
+ def _get_uncovered_rpc_commands(self):
+ """
+ Return a set of currently untested RPC commands.
+
+ """
+ # This is shared from `test/functional/test-framework/coverage.py`
+ reference_filename = 'rpc_interface.txt'
+ coverage_file_prefix = 'coverage.'
+
+ coverage_ref_filename = os.path.join(self.dir, reference_filename)
+ coverage_filenames = set()
+ all_cmds = set()
+ covered_cmds = set()
+
+ if not os.path.isfile(coverage_ref_filename):
+ raise RuntimeError("No coverage reference found")
+
+ with open(coverage_ref_filename, 'r') as f:
+ all_cmds.update([i.strip() for i in f.readlines()])
+
+ for root, dirs, files in os.walk(self.dir):
+ for filename in files:
+ if filename.startswith(coverage_file_prefix):
+ coverage_filenames.add(os.path.join(root, filename))
+
+ for filename in coverage_filenames:
+ with open(filename, 'r') as f:
+ covered_cmds.update([i.strip() for i in f.readlines()])
+
+ return all_cmds - covered_cmds
+
+
+if __name__ == '__main__':
+ main()
diff --git a/qa/rpc-tests/txn_clone.py b/test/functional/txn_clone.py
index 22f850ece6..9b81af96cf 100755
--- a/qa/rpc-tests/txn_clone.py
+++ b/test/functional/txn_clone.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-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.
-
-#
-# Test proper accounting with an equivalent malleability clone
-#
+"""Test the wallet accounts properly when there are cloned transactions with malleated scriptsigs."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -23,7 +20,9 @@ class TxnMallTest(BitcoinTestFramework):
def setup_network(self):
# Start with split network:
- return super(TxnMallTest, self).setup_network(True)
+ super(TxnMallTest, self).setup_network()
+ disconnect_nodes(self.nodes[1], 2)
+ disconnect_nodes(self.nodes[2], 1)
def run_test(self):
# All nodes should start with 1,250 BTC:
diff --git a/qa/rpc-tests/txn_doublespend.py b/test/functional/txn_doublespend.py
index 84944c3c19..1bd3b3271c 100755
--- a/qa/rpc-tests/txn_doublespend.py
+++ b/test/functional/txn_doublespend.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-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.
-
-#
-# Test proper accounting with a double-spend conflict
-#
+"""Test the wallet accounts properly when there is a double-spend conflict."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -23,7 +20,9 @@ class TxnMallTest(BitcoinTestFramework):
def setup_network(self):
# Start with split network:
- return super(TxnMallTest, self).setup_network(True)
+ super().setup_network()
+ disconnect_nodes(self.nodes[1], 2)
+ disconnect_nodes(self.nodes[2], 1)
def run_test(self):
# All nodes should start with 1,250 BTC:
diff --git a/test/functional/wallet-accounts.py b/test/functional/wallet-accounts.py
new file mode 100755
index 0000000000..e6635bea1c
--- /dev/null
+++ b/test/functional/wallet-accounts.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Test account RPCs.
+
+RPCs tested are:
+ - getaccountaddress
+ - getaddressesbyaccount
+ - listaddressgroupings
+ - setaccount
+ - sendfrom (with account arguments)
+ - move (with account arguments)
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+)
+
+class WalletAccountsTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+ self.extra_args = [[]]
+
+ def run_test(self):
+ node = self.nodes[0]
+ # Check that there's no UTXO on any of the nodes
+ assert_equal(len(node.listunspent()), 0)
+
+ # Note each time we call generate, all generated coins go into
+ # the same address, so we call twice to get two addresses w/50 each
+ node.generate(1)
+ node.generate(101)
+ assert_equal(node.getbalance(), 100)
+
+ # there should be 2 address groups
+ # each with 1 address with a balance of 50 Bitcoins
+ address_groups = node.listaddressgroupings()
+ assert_equal(len(address_groups), 2)
+ # the addresses aren't linked now, but will be after we send to the
+ # common address
+ linked_addresses = set()
+ for address_group in address_groups:
+ assert_equal(len(address_group), 1)
+ assert_equal(len(address_group[0]), 2)
+ assert_equal(address_group[0][1], 50)
+ linked_addresses.add(address_group[0][0])
+
+ # send 50 from each address to a third address not in this wallet
+ # There's some fee that will come back to us when the miner reward
+ # matures.
+ common_address = "msf4WtN1YQKXvNtvdFYt9JBnUD2FB41kjr"
+ txid = node.sendmany(
+ fromaccount="",
+ amounts={common_address: 100},
+ subtractfeefrom=[common_address],
+ minconf=1,
+ )
+ tx_details = node.gettransaction(txid)
+ fee = -tx_details['details'][0]['fee']
+ # there should be 1 address group, with the previously
+ # unlinked addresses now linked (they both have 0 balance)
+ address_groups = node.listaddressgroupings()
+ assert_equal(len(address_groups), 1)
+ assert_equal(len(address_groups[0]), 2)
+ assert_equal(set([a[0] for a in address_groups[0]]), linked_addresses)
+ assert_equal([a[1] for a in address_groups[0]], [0, 0])
+
+ node.generate(1)
+
+ # we want to reset so that the "" account has what's expected.
+ # otherwise we're off by exactly the fee amount as that's mined
+ # and matures in the next 100 blocks
+ node.sendfrom("", common_address, fee)
+ accounts = ["a", "b", "c", "d", "e"]
+ amount_to_send = 1.0
+ account_addresses = dict()
+ for account in accounts:
+ address = node.getaccountaddress(account)
+ account_addresses[account] = address
+
+ node.getnewaddress(account)
+ assert_equal(node.getaccount(address), account)
+ assert(address in node.getaddressesbyaccount(account))
+
+ node.sendfrom("", address, amount_to_send)
+
+ node.generate(1)
+
+ for i in range(len(accounts)):
+ from_account = accounts[i]
+ to_account = accounts[(i+1) % len(accounts)]
+ to_address = account_addresses[to_account]
+ node.sendfrom(from_account, to_address, amount_to_send)
+
+ node.generate(1)
+
+ for account in accounts:
+ address = node.getaccountaddress(account)
+ assert(address != account_addresses[account])
+ assert_equal(node.getreceivedbyaccount(account), 2)
+ node.move(account, "", node.getbalance(account))
+
+ node.generate(101)
+
+ expected_account_balances = {"": 5200}
+ for account in accounts:
+ expected_account_balances[account] = 0
+
+ assert_equal(node.listaccounts(), expected_account_balances)
+
+ assert_equal(node.getbalance(""), 5200)
+
+ for account in accounts:
+ address = node.getaccountaddress("")
+ node.setaccount(address, account)
+ assert(address in node.getaddressesbyaccount(account))
+ assert(address not in node.getaddressesbyaccount(""))
+
+ for account in accounts:
+ addresses = []
+ for x in range(10):
+ addresses.append(node.getnewaddress())
+ multisig_address = node.addmultisigaddress(5, addresses, account)
+ node.sendfrom("", multisig_address, 50)
+
+ node.generate(101)
+
+ for account in accounts:
+ assert_equal(node.getbalance(account), 50)
+
+if __name__ == '__main__':
+ WalletAccountsTest().main()
diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py
new file mode 100755
index 0000000000..8876f935a4
--- /dev/null
+++ b/test/functional/wallet-dump.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+"""Test the dumpwallet RPC."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (start_nodes, start_node, assert_equal, bitcoind_processes)
+
+
+def read_dump(file_name, addrs, hd_master_addr_old):
+ """
+ Read the given dump, count the addrs that match, count change and reserve.
+ Also check that the old hd_master is inactive
+ """
+ with open(file_name, encoding='utf8') as inputfile:
+ found_addr = 0
+ found_addr_chg = 0
+ found_addr_rsv = 0
+ hd_master_addr_ret = None
+ for line in inputfile:
+ # only read non comment lines
+ if line[0] != "#" and len(line) > 10:
+ # split out some data
+ key_label, comment = line.split("#")
+ # key = key_label.split(" ")[0]
+ keytype = key_label.split(" ")[2]
+ if len(comment) > 1:
+ addr_keypath = comment.split(" addr=")[1]
+ addr = addr_keypath.split(" ")[0]
+ keypath = None
+ if keytype == "inactivehdmaster=1":
+ # ensure the old master is still available
+ assert(hd_master_addr_old == addr)
+ elif keytype == "hdmaster=1":
+ # ensure we have generated a new hd master key
+ assert(hd_master_addr_old != addr)
+ hd_master_addr_ret = addr
+ else:
+ keypath = addr_keypath.rstrip().split("hdkeypath=")[1]
+
+ # count key types
+ for addrObj in addrs:
+ if addrObj['address'] == addr and addrObj['hdkeypath'] == keypath and keytype == "label=":
+ found_addr += 1
+ break
+ elif keytype == "change=1":
+ found_addr_chg += 1
+ break
+ elif keytype == "reserve=1":
+ found_addr_rsv += 1
+ break
+ return found_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret
+
+
+class WalletDumpTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = False
+ self.num_nodes = 1
+ self.extra_args = [["-keypool=90"]]
+
+ def setup_network(self, split=False):
+ # Use 1 minute timeout because the initial getnewaddress RPC can take
+ # longer than the default 30 seconds due to an expensive
+ # CWallet::TopUpKeyPool call, and the encryptwallet RPC made later in
+ # the test often takes even longer.
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60)
+
+ def run_test (self):
+ tmpdir = self.options.tmpdir
+
+ # generate 20 addresses to compare against the dump
+ test_addr_count = 20
+ addrs = []
+ for i in range(0,test_addr_count):
+ addr = self.nodes[0].getnewaddress()
+ vaddr= self.nodes[0].validateaddress(addr) #required to get hd keypath
+ addrs.append(vaddr)
+ # Should be a no-op:
+ self.nodes[0].keypoolrefill()
+
+ # dump unencrypted wallet
+ self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.unencrypted.dump")
+
+ found_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc = \
+ read_dump(tmpdir + "/node0/wallet.unencrypted.dump", addrs, None)
+ assert_equal(found_addr, test_addr_count) # all keys must be in the dump
+ assert_equal(found_addr_chg, 50) # 50 blocks where mined
+ assert_equal(found_addr_rsv, 90*2) # 90 keys plus 100% internal keys
+
+ #encrypt wallet, restart, unlock and dump
+ self.nodes[0].encryptwallet('test')
+ bitcoind_processes[0].wait()
+ self.nodes[0] = start_node(0, self.options.tmpdir, self.extra_args[0])
+ self.nodes[0].walletpassphrase('test', 10)
+ # Should be a no-op:
+ self.nodes[0].keypoolrefill()
+ self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.encrypted.dump")
+
+ found_addr, found_addr_chg, found_addr_rsv, hd_master_addr_enc = \
+ read_dump(tmpdir + "/node0/wallet.encrypted.dump", addrs, hd_master_addr_unenc)
+ assert_equal(found_addr, test_addr_count)
+ assert_equal(found_addr_chg, 90*2 + 50) # old reserve keys are marked as change now
+ assert_equal(found_addr_rsv, 90*2)
+
+if __name__ == '__main__':
+ WalletDumpTest().main ()
diff --git a/qa/rpc-tests/wallet-hd.py b/test/functional/wallet-hd.py
index c738ee2207..aab3b4bc2d 100755
--- a/qa/rpc-tests/wallet-hd.py
+++ b/test/functional/wallet-hd.py
@@ -2,13 +2,14 @@
# Copyright (c) 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.
+"""Test Hierarchical Deterministic wallet function."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
- start_nodes,
start_node,
assert_equal,
connect_nodes_bi,
+ assert_start_raises_init_error
)
import os
import shutil
@@ -20,27 +21,33 @@ class WalletHDTest(BitcoinTestFramework):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 2
- self.node_args = [['-usehd=0'], ['-usehd=1', '-keypool=0']]
-
- def setup_network(self):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.node_args)
- self.is_network_split = False
- connect_nodes_bi(self.nodes, 0, 1)
+ self.extra_args = [['-usehd=0'], ['-usehd=1', '-keypool=0']]
def run_test (self):
tmpdir = self.options.tmpdir
+ # Make sure can't switch off usehd after wallet creation
+ self.stop_node(1)
+ assert_start_raises_init_error(1, self.options.tmpdir, ['-usehd=0'], 'already existing HD wallet')
+ self.nodes[1] = start_node(1, self.options.tmpdir, self.extra_args[1])
+ connect_nodes_bi(self.nodes, 0, 1)
+
# Make sure we use hd, keep masterkeyid
- masterkeyid = self.nodes[1].getwalletinfo()['masterkeyid']
+ masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid']
assert_equal(len(masterkeyid), 40)
+ # create an internal key
+ change_addr = self.nodes[1].getrawchangeaddress()
+ change_addrV= self.nodes[1].validateaddress(change_addr)
+ assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") #first internal child key
+
# Import a non-HD private key in the HD wallet
non_hd_add = self.nodes[0].getnewaddress()
self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))
# This should be enough to keep the master key and the non-HD key
- self.nodes[1].backupwallet(tmpdir + "hd.bak")
- #self.nodes[1].dumpwallet(tmpdir + "hd.dump")
+ self.nodes[1].backupwallet(tmpdir + "/hd.bak")
+ #self.nodes[1].dumpwallet(tmpdir + "/hd.dump")
# Derive some HD addresses and remember the last
# Also send funds to each add
@@ -57,14 +64,19 @@ class WalletHDTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(non_hd_add, 1)
self.nodes[0].generate(1)
+ # create an internal key (again)
+ change_addr = self.nodes[1].getrawchangeaddress()
+ change_addrV= self.nodes[1].validateaddress(change_addr)
+ assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") #second internal child key
+
self.sync_all()
assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
- print("Restore backup ...")
+ self.log.info("Restore backup ...")
self.stop_node(1)
os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat")
- shutil.copyfile(tmpdir + "hd.bak", tmpdir + "/node1/regtest/wallet.dat")
- self.nodes[1] = start_node(1, self.options.tmpdir, self.node_args[1])
+ shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat")
+ self.nodes[1] = start_node(1, self.options.tmpdir, self.extra_args[1])
#connect_nodes_bi(self.nodes, 0, 1)
# Assert that derivation is deterministic
@@ -78,10 +90,19 @@ class WalletHDTest(BitcoinTestFramework):
# Needs rescan
self.stop_node(1)
- self.nodes[1] = start_node(1, self.options.tmpdir, self.node_args[1] + ['-rescan'])
+ self.nodes[1] = start_node(1, self.options.tmpdir, self.extra_args[1] + ['-rescan'])
#connect_nodes_bi(self.nodes, 0, 1)
assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
+ # send a tx and make sure its using the internal chain for the changeoutput
+ txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+ outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout']
+ keypath = ""
+ for out in outs:
+ if out['value'] != 1:
+ keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath']
+
+ assert_equal(keypath[0:7], "m/0'/1'")
if __name__ == '__main__':
WalletHDTest().main ()
diff --git a/qa/rpc-tests/wallet.py b/test/functional/wallet.py
index 5d96e7a6e5..57f6dfdaa9 100755
--- a/qa/rpc-tests/wallet.py
+++ b/test/functional/wallet.py
@@ -2,11 +2,11 @@
# Copyright (c) 2014-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.
-
+"""Test the wallet."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-class WalletTest (BitcoinTestFramework):
+class WalletTest(BitcoinTestFramework):
def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size):
"""Return curr_balance after asserting the fee was in range"""
@@ -18,23 +18,23 @@ class WalletTest (BitcoinTestFramework):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 4
+ self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)]
- def setup_network(self, split=False):
- self.nodes = start_nodes(3, self.options.tmpdir)
+ def setup_network(self):
+ self.nodes = start_nodes(3, self.options.tmpdir, self.extra_args[:3])
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
- self.is_network_split=False
self.sync_all()
- def run_test (self):
+ def run_test(self):
# Check that there's no UTXO on none of the nodes
assert_equal(len(self.nodes[0].listunspent()), 0)
assert_equal(len(self.nodes[1].listunspent()), 0)
assert_equal(len(self.nodes[2].listunspent()), 0)
- print("Mining blocks...")
+ self.log.info("Mining blocks...")
self.nodes[0].generate(1)
@@ -51,13 +51,33 @@ class WalletTest (BitcoinTestFramework):
assert_equal(self.nodes[2].getbalance(), 0)
# Check that only first and second nodes have UTXOs
- assert_equal(len(self.nodes[0].listunspent()), 1)
+ utxos = self.nodes[0].listunspent()
+ assert_equal(len(utxos), 1)
assert_equal(len(self.nodes[1].listunspent()), 1)
assert_equal(len(self.nodes[2].listunspent()), 0)
# Send 21 BTC from 0 to 2 using sendtoaddress call.
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)
- self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)
+ mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)
+
+ self.log.info("test gettxout")
+ # utxo spent in mempool should be visible if you exclude mempool
+ # but invisible if you include mempool
+ confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"]
+ txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False)
+ assert_equal(txout['value'], 50)
+ txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True)
+ assert txout is None
+ # new utxo from mempool should be invisible if you exclude mempool
+ # but visible if you include mempool
+ txout = self.nodes[0].gettxout(mempool_txid, 0, False)
+ assert txout is None
+ txout1 = self.nodes[0].gettxout(mempool_txid, 0, True)
+ txout2 = self.nodes[0].gettxout(mempool_txid, 1, True)
+ # note the mempool tx will have randomly assigned indices
+ # but 10 will go to node2 and the rest will go to node0
+ balance = self.nodes[0].getbalance()
+ assert_equal(set([txout1['value'], txout2['value']]), set([10, balance]))
walletinfo = self.nodes[0].getwalletinfo()
assert_equal(walletinfo['immature_balance'], 0)
@@ -70,7 +90,7 @@ class WalletTest (BitcoinTestFramework):
unspent_0 = self.nodes[2].listunspent()[0]
unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]}
self.nodes[2].lockunspent(False, [unspent_0])
- assert_raises(JSONRPCException, self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20)
+ assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20)
assert_equal([unspent_0], self.nodes[2].listlockunspent())
self.nodes[2].lockunspent(True, [unspent_0])
assert_equal(len(self.nodes[2].listlockunspent()), 0)
@@ -154,7 +174,7 @@ class WalletTest (BitcoinTestFramework):
txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
sync_mempools(self.nodes)
- self.nodes.append(start_node(3, self.options.tmpdir))
+ self.nodes.append(start_node(3, self.options.tmpdir, self.extra_args[3]))
connect_nodes_bi(self.nodes, 0, 3)
sync_blocks(self.nodes)
@@ -198,7 +218,6 @@ class WalletTest (BitcoinTestFramework):
#do some -walletbroadcast tests
stop_nodes(self.nodes)
- wait_bitcoinds()
self.nodes = start_nodes(3, self.options.tmpdir, [["-walletbroadcast=0"],["-walletbroadcast=0"],["-walletbroadcast=0"]])
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
@@ -224,7 +243,6 @@ class WalletTest (BitcoinTestFramework):
#restart the nodes with -walletbroadcast=1
stop_nodes(self.nodes)
- wait_bitcoinds()
self.nodes = start_nodes(3, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
@@ -252,19 +270,11 @@ class WalletTest (BitcoinTestFramework):
txObj = self.nodes[0].gettransaction(txId)
assert_equal(txObj['amount'], Decimal('-0.0001'))
- try:
- txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4")
- except JSONRPCException as e:
- assert("Invalid amount" in e.error['message'])
- else:
- raise AssertionError("Must not parse invalid amounts")
+ # This will raise an exception because the amount type is wrong
+ assert_raises_jsonrpc(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4")
-
- try:
- self.nodes[0].generate("2")
- raise AssertionError("Must not accept strings as numeric")
- except JSONRPCException as e:
- assert("not an integer" in e.error['message'])
+ # This will raise an exception since generate does not accept a string
+ assert_raises_jsonrpc(-1, "not an integer", self.nodes[0].generate, "2")
# Import address and private key to check correct behavior of spendable unspents
# 1. Send some coins to generate new UTXO
@@ -331,11 +341,12 @@ class WalletTest (BitcoinTestFramework):
# disabled until issue is fixed: https://github.com/bitcoin/bitcoin/issues/7463
# '-salvagewallet',
]
+ chainlimit = 6
for m in maintenance:
- print("check " + m)
+ self.log.info("check " + m)
stop_nodes(self.nodes)
- wait_bitcoinds()
- self.nodes = start_nodes(3, self.options.tmpdir, [[m]] * 3)
+ # set lower ancestor limit for later
+ self.nodes = start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3)
while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]:
# reindex will leave rpc warm up "early"; Wait for it to finish
time.sleep(0.1)
@@ -348,5 +359,56 @@ class WalletTest (BitcoinTestFramework):
assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1])
assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0)
+ # ==Check that wallet prefers to use coins that don't exceed mempool limits =====
+
+ # Get all non-zero utxos together
+ chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()]
+ singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True)
+ self.nodes[0].generate(1)
+ node0_balance = self.nodes[0].getbalance()
+ # Split into two chains
+ rawtx = self.nodes[0].createrawtransaction([{"txid":singletxid, "vout":0}], {chain_addrs[0]:node0_balance/2-Decimal('0.01'), chain_addrs[1]:node0_balance/2-Decimal('0.01')})
+ signedtx = self.nodes[0].signrawtransaction(rawtx)
+ singletxid = self.nodes[0].sendrawtransaction(signedtx["hex"])
+ self.nodes[0].generate(1)
+
+ # Make a long chain of unconfirmed payments without hitting mempool limit
+ # Each tx we make leaves only one output of change on a chain 1 longer
+ # Since the amount to send is always much less than the outputs, we only ever need one output
+ # So we should be able to generate exactly chainlimit txs for each original output
+ sending_addr = self.nodes[1].getnewaddress()
+ txid_list = []
+ for i in range(chainlimit*2):
+ txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')))
+ assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit*2)
+ assert_equal(len(txid_list), chainlimit*2)
+
+ # Without walletrejectlongchains, we will still generate a txid
+ # The tx will be stored in the wallet but not accepted to the mempool
+ extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))
+ assert(extra_txid not in self.nodes[0].getrawmempool())
+ assert(extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()])
+ self.nodes[0].abandontransaction(extra_txid)
+ total_txs = len(self.nodes[0].listtransactions("*",99999))
+
+ # Try with walletrejectlongchains
+ # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf
+ stop_node(self.nodes[0],0)
+ self.nodes[0] = start_node(0, self.options.tmpdir, ["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)])
+
+ # wait for loadmempool
+ timeout = 10
+ while (timeout > 0 and len(self.nodes[0].getrawmempool()) < chainlimit*2):
+ time.sleep(0.5)
+ timeout -= 0.5
+ assert_equal(len(self.nodes[0].getrawmempool()), chainlimit*2)
+
+ node0_balance = self.nodes[0].getbalance()
+ # With walletrejectlongchains we will not create the tx and store it in our wallet.
+ assert_raises_jsonrpc(-4, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01'))
+
+ # Verify nothing new in wallet
+ assert_equal(total_txs, len(self.nodes[0].listtransactions("*",99999)))
+
if __name__ == '__main__':
WalletTest().main()
diff --git a/qa/rpc-tests/walletbackup.py b/test/functional/walletbackup.py
index b991d5c761..0492132af6 100755
--- a/qa/rpc-tests/walletbackup.py
+++ b/test/functional/walletbackup.py
@@ -2,9 +2,7 @@
# Copyright (c) 2014-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.
-
-"""
-Exercise the wallet backup code. Ported from walletbackup.sh.
+"""Test the wallet backup features.
Test case is:
4 nodes. 1 2 and 3 send transactions between each other,
@@ -36,8 +34,6 @@ and confirm again balances are correct.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from random import randint
-import logging
-logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout)
class WalletBackupTest(BitcoinTestFramework):
@@ -45,17 +41,15 @@ class WalletBackupTest(BitcoinTestFramework):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 4
+ # nodes 1, 2,3 are spenders, let's give them a keypool=100
+ self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
- # This mirrors how the network was setup in the bash test
def setup_network(self, split=False):
- # nodes 1, 2,3 are spenders, let's give them a keypool=100
- extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ self.setup_nodes()
connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[1], 3)
connect_nodes(self.nodes[2], 3)
connect_nodes(self.nodes[2], 0)
- self.is_network_split=False
self.sync_all()
def one_send(self, from_node, to_address):
@@ -79,6 +73,7 @@ class WalletBackupTest(BitcoinTestFramework):
# Must sync mempools before mining.
sync_mempools(self.nodes)
self.nodes[3].generate(1)
+ sync_blocks(self.nodes)
# As above, this mirrors the original bash test.
def start_three(self):
@@ -101,7 +96,7 @@ class WalletBackupTest(BitcoinTestFramework):
os.remove(self.options.tmpdir + "/node2/regtest/wallet.dat")
def run_test(self):
- logging.info("Generating initial blockchain")
+ self.log.info("Generating initial blockchain")
self.nodes[0].generate(1)
sync_blocks(self.nodes)
self.nodes[1].generate(1)
@@ -116,12 +111,12 @@ class WalletBackupTest(BitcoinTestFramework):
assert_equal(self.nodes[2].getbalance(), 50)
assert_equal(self.nodes[3].getbalance(), 0)
- logging.info("Creating transactions")
+ self.log.info("Creating transactions")
# Five rounds of sending each other transactions.
for i in range(5):
self.do_one_round()
- logging.info("Backing up")
+ self.log.info("Backing up")
tmpdir = self.options.tmpdir
self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak")
self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump")
@@ -130,7 +125,7 @@ class WalletBackupTest(BitcoinTestFramework):
self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak")
self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump")
- logging.info("More transactions")
+ self.log.info("More transactions")
for i in range(5):
self.do_one_round()
@@ -151,7 +146,7 @@ class WalletBackupTest(BitcoinTestFramework):
##
# Test restoring spender wallets from backups
##
- logging.info("Restoring using wallet.dat")
+ self.log.info("Restoring using wallet.dat")
self.stop_three()
self.erase_three()
@@ -164,7 +159,7 @@ class WalletBackupTest(BitcoinTestFramework):
shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallet.dat")
- logging.info("Re-starting nodes")
+ self.log.info("Re-starting nodes")
self.start_three()
sync_blocks(self.nodes)
@@ -172,7 +167,7 @@ class WalletBackupTest(BitcoinTestFramework):
assert_equal(self.nodes[1].getbalance(), balance1)
assert_equal(self.nodes[2].getbalance(), balance2)
- logging.info("Restoring using dumped wallet")
+ self.log.info("Restoring using dumped wallet")
self.stop_three()
self.erase_three()
diff --git a/qa/rpc-tests/zapwallettxes.py b/test/functional/zapwallettxes.py
index 17ba53a844..7987edeb54 100755
--- a/qa/rpc-tests/zapwallettxes.py
+++ b/test/functional/zapwallettxes.py
@@ -2,7 +2,16 @@
# Copyright (c) 2014-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.
+"""Test the zapwallettxes functionality.
+- start three bitcoind nodes
+- create four transactions on node 0 - two are confirmed and two are
+ unconfirmed.
+- restart node 1 and verify that both the confirmed and the unconfirmed
+ transactions are still available.
+- restart node 0 and verify that the confirmed transactions are still
+ available, but that the unconfirmed transaction has been zapped.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -14,16 +23,12 @@ class ZapWalletTXesTest (BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 3
- def setup_network(self, split=False):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
- connect_nodes_bi(self.nodes,0,1)
- connect_nodes_bi(self.nodes,1,2)
+ def setup_network(self):
+ super().setup_network()
connect_nodes_bi(self.nodes,0,2)
- self.is_network_split=False
- self.sync_all()
def run_test (self):
- print("Mining blocks...")
+ self.log.info("Mining blocks...")
self.nodes[0].generate(1)
self.sync_all()
self.nodes[1].generate(101)
diff --git a/qa/rpc-tests/zmq_test.py b/test/functional/zmq_test.py
index 3a116317fe..918e13bcd4 100755
--- a/qa/rpc-tests/zmq_test.py
+++ b/test/functional/zmq_test.py
@@ -2,18 +2,14 @@
# Copyright (c) 2015-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.
-
-#
-# Test ZMQ interface
-#
+"""Test the ZMQ API."""
+import configparser
+import os
+import struct
+import sys
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-import zmq
-import struct
-
-import http.client
-import urllib.parse
class ZMQTest (BitcoinTestFramework):
@@ -24,12 +20,29 @@ class ZMQTest (BitcoinTestFramework):
port = 28332
def setup_nodes(self):
+ # Try to import python3-zmq. Skip this test if the import fails.
+ try:
+ import zmq
+ except ImportError:
+ self.log.warning("python3-zmq module not available. Skipping zmq tests!")
+ sys.exit(self.TEST_EXIT_SKIPPED)
+
+ # Check that bitcoin has been built with ZMQ enabled
+ config = configparser.ConfigParser()
+ if not self.options.configfile:
+ self.options.configfile = os.path.dirname(__file__) + "/config.ini"
+ config.read_file(open(self.options.configfile))
+
+ if not config["components"].getboolean("ENABLE_ZMQ"):
+ self.log.warning("bitcoind has not been built with zmq enabled. Skipping zmq tests!")
+ sys.exit(self.TEST_EXIT_SKIPPED)
+
self.zmqContext = zmq.Context()
self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock")
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx")
self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % self.port)
- return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
['-zmqpubhashtx=tcp://127.0.0.1:'+str(self.port), '-zmqpubhashblock=tcp://127.0.0.1:'+str(self.port)],
[],
[],
@@ -42,12 +55,11 @@ class ZMQTest (BitcoinTestFramework):
genhashes = self.nodes[0].generate(1)
self.sync_all()
- print("listen...")
+ self.log.info("listen...")
msg = self.zmqSubSocket.recv_multipart()
topic = msg[0]
assert_equal(topic, b"hashtx")
body = msg[1]
- nseq = msg[2]
msgSequence = struct.unpack('<I', msg[-1])[-1]
assert_equal(msgSequence, 0) #must be sequence 0 on hashtx
diff --git a/test/util/bctest.py b/test/util/bctest.py
new file mode 100644
index 0000000000..b17cf77ae3
--- /dev/null
+++ b/test/util/bctest.py
@@ -0,0 +1,139 @@
+# 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
+import pprint
+
+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, buildenv):
+ """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 = buildenv.BUILDDIR + "/src/" + testObj['exec'] + buildenv.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:
+ data_mismatch, formatting_mismatch = False, False
+ # 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 + ")")
+ data_mismatch = True
+ # 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)
+ formatting_mismatch = True
+
+ assert not data_mismatch and not formatting_mismatch
+
+ # 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
+
+ if "error_txt" in testObj:
+ want_error = testObj["error_txt"]
+ # Compare error text
+ # TODO: ideally, we'd compare the strings exactly and also assert
+ # That stderr is empty if no errors are expected. However, bitcoin-tx
+ # emits DISPLAY errors when running as a windows application on
+ # linux through wine. Just assert that the expected error text appears
+ # somewhere in stderr.
+ if want_error not in outs[1]:
+ logging.error("Error mismatch:\n" + "Expected: " + want_error + "\nReceived: " + outs[1].rstrip())
+ 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)
+ logging.info("PASSED: " + testObj["description"])
+ except:
+ logging.info("FAILED: " + testObj["description"])
+ failed_testcases.append(testObj["description"])
+
+ if failed_testcases:
+ error_message = "FAILED_TESTCASES:\n"
+ error_message += pprint.pformat(failed_testcases, width=400)
+ logging.error(error_message)
+ sys.exit(1)
+ else:
+ sys.exit(0)
diff --git a/test/util/bitcoin-util-test.py b/test/util/bitcoin-util-test.py
new file mode 100755
index 0000000000..e09a25159d
--- /dev/null
+++ b/test/util/bitcoin-util-test.py
@@ -0,0 +1,36 @@
+#!/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 argparse
+import logging
+
+help_text="""Test framework for bitcoin utils.
+
+Runs automatically during `make check`.
+
+Can also be run manually."""
+
+if __name__ == '__main__':
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+ import buildenv
+ import bctest
+
+ parser = argparse.ArgumentParser(description=help_text)
+ parser.add_argument('-v', '--verbose', action='store_true')
+ args = parser.parse_args()
+ 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(buildenv.SRCDIR + "/test/util/data", "bitcoin-util-test.json", buildenv)
diff --git a/test/util/buildenv.py.in b/test/util/buildenv.py.in
new file mode 100644
index 0000000000..33030b0348
--- /dev/null
+++ b/test/util/buildenv.py.in
@@ -0,0 +1,4 @@
+#!/usr/bin/env python
+exeext="@EXEEXT@"
+SRCDIR="@abs_top_srcdir@"
+BUILDDIR="@abs_top_builddir@"
diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json
new file mode 100644
index 0000000000..b61a4f7f8f
--- /dev/null
+++ b/test/util/data/bitcoin-util-test.json
@@ -0,0 +1,392 @@
+[
+ { "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,
+ "error_txt": "error: Invalid TX input index '31'",
+ "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,
+ "error_txt": "error: Invalid TX output index '2'",
+ "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",
+ "outaddr=1"],
+ "return_code": 1,
+ "error_txt": "error: TX output missing or too many separators",
+ "description": "Malformed outaddr argument (no address specified). Expected to fail."
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "outaddr=1:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o:garbage"],
+ "return_code": 1,
+ "error_txt": "error: TX output missing or too many separators",
+ "description": "Malformed outaddr argument (too many separators). Expected to fail."
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "outpubkey=0"],
+ "return_code": 1,
+ "error_txt": "error: TX output missing or too many separators",
+ "description": "Malformed outpubkey argument (no pubkey specified). Expected to fail."
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:W:non53nse"],
+ "return_code": 1,
+ "error_txt": "error: TX output missing or too many separators",
+ "description": "Malformed outpubkey argument (too many separators). Expected to fail."
+ },
+ { "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,
+ "error_txt": "error: invalid TX output data",
+ "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,
+ "error_txt": "error: invalid TX output data",
+ "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/blanktx.hex b/test/util/data/blanktxv1.hex
index 36b6f00fb6..36b6f00fb6 100644
--- a/src/test/data/blanktx.hex
+++ b/test/util/data/blanktxv1.hex
diff --git a/test/util/data/blanktxv1.json b/test/util/data/blanktxv1.json
new file mode 100644
index 0000000000..9fe2de649b
--- /dev/null
+++ b/test/util/data/blanktxv1.json
@@ -0,0 +1,13 @@
+{
+ "txid": "d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43",
+ "hash": "d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43",
+ "version": 1,
+ "size": 10,
+ "vsize": 10,
+ "locktime": 0,
+ "vin": [
+ ],
+ "vout": [
+ ],
+ "hex": "01000000000000000000"
+}
diff --git a/test/util/data/blanktxv2.hex b/test/util/data/blanktxv2.hex
new file mode 100644
index 0000000000..22d830eda1
--- /dev/null
+++ b/test/util/data/blanktxv2.hex
@@ -0,0 +1 @@
+02000000000000000000
diff --git a/test/util/data/blanktxv2.json b/test/util/data/blanktxv2.json
new file mode 100644
index 0000000000..e97626e421
--- /dev/null
+++ b/test/util/data/blanktxv2.json
@@ -0,0 +1,13 @@
+{
+ "txid": "4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a",
+ "hash": "4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a",
+ "version": 2,
+ "size": 10,
+ "vsize": 10,
+ "locktime": 0,
+ "vin": [
+ ],
+ "vout": [
+ ],
+ "hex": "02000000000000000000"
+}
diff --git a/src/test/data/tt-delin1-out.hex b/test/util/data/tt-delin1-out.hex
index 42ad840f43..42ad840f43 100644
--- a/src/test/data/tt-delin1-out.hex
+++ b/test/util/data/tt-delin1-out.hex
diff --git a/test/util/data/tt-delin1-out.json b/test/util/data/tt-delin1-out.json
new file mode 100644
index 0000000000..f6dfbb51cc
--- /dev/null
+++ b/test/util/data/tt-delin1-out.json
@@ -0,0 +1,219 @@
+{
+ "txid": "81b2035be1da1abe745c6141174a73d151009ec17b3d5ebffa2e177408c50dfd",
+ "hash": "81b2035be1da1abe745c6141174a73d151009ec17b3d5ebffa2e177408c50dfd",
+ "version": 1,
+ "size": 3040,
+ "vsize": 3040,
+ "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/test/util/data/tt-delout1-out.hex
index cc60c3fac6..cc60c3fac6 100644
--- a/src/test/data/tt-delout1-out.hex
+++ b/test/util/data/tt-delout1-out.hex
diff --git a/test/util/data/tt-delout1-out.json b/test/util/data/tt-delout1-out.json
new file mode 100644
index 0000000000..6769ed79ff
--- /dev/null
+++ b/test/util/data/tt-delout1-out.json
@@ -0,0 +1,215 @@
+{
+ "txid": "c46ccd75b5050e942b2e86a3648f843f525fe6fc000bf0534ba5973063354493",
+ "hash": "c46ccd75b5050e942b2e86a3648f843f525fe6fc000bf0534ba5973063354493",
+ "version": 1,
+ "size": 3155,
+ "vsize": 3155,
+ "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/test/util/data/tt-locktime317000-out.hex
index 287f420a40..287f420a40 100644
--- a/src/test/data/tt-locktime317000-out.hex
+++ b/test/util/data/tt-locktime317000-out.hex
diff --git a/test/util/data/tt-locktime317000-out.json b/test/util/data/tt-locktime317000-out.json
new file mode 100644
index 0000000000..82b64df075
--- /dev/null
+++ b/test/util/data/tt-locktime317000-out.json
@@ -0,0 +1,228 @@
+{
+ "txid": "aded538f642c17e15f4d3306b8be7e1a4d1ae0c4616d641ab51ea09ba65e5cb5",
+ "hash": "aded538f642c17e15f4d3306b8be7e1a4d1ae0c4616d641ab51ea09ba65e5cb5",
+ "version": 1,
+ "size": 3189,
+ "vsize": 3189,
+ "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/test/util/data/tx394b54bb.hex
index 33f26cb4d6..33f26cb4d6 100644
--- a/src/test/data/tx394b54bb.hex
+++ b/test/util/data/tx394b54bb.hex
diff --git a/src/test/data/txcreate1.hex b/test/util/data/txcreate1.hex
index e2981a51c9..9ec6ee3531 100644
--- a/src/test/data/txcreate1.hex
+++ b/test/util/data/txcreate1.hex
@@ -1 +1 @@
-01000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000
+02000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000
diff --git a/test/util/data/txcreate1.json b/test/util/data/txcreate1.json
new file mode 100644
index 0000000000..36741044c9
--- /dev/null
+++ b/test/util/data/txcreate1.json
@@ -0,0 +1,66 @@
+{
+ "txid": "fe7d174f42dce0cffa7a527e9bc8368956057619ec817648f6138b98f2533e8f",
+ "hash": "fe7d174f42dce0cffa7a527e9bc8368956057619ec817648f6138b98f2533e8f",
+ "version": 2,
+ "size": 201,
+ "vsize": 201,
+ "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/test/util/data/txcreate2.hex b/test/util/data/txcreate2.hex
new file mode 100644
index 0000000000..38bb7b1046
--- /dev/null
+++ b/test/util/data/txcreate2.hex
@@ -0,0 +1 @@
+02000000000100000000000000000000000000
diff --git a/test/util/data/txcreate2.json b/test/util/data/txcreate2.json
new file mode 100644
index 0000000000..23fe7ace67
--- /dev/null
+++ b/test/util/data/txcreate2.json
@@ -0,0 +1,22 @@
+{
+ "txid": "0481afb29931341d0d7861d8a2f6f26456fa042abf54a23e96440ed7946e0715",
+ "hash": "0481afb29931341d0d7861d8a2f6f26456fa042abf54a23e96440ed7946e0715",
+ "version": 2,
+ "size": 19,
+ "vsize": 19,
+ "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/test/util/data/txcreatedata1.hex
index eccc7604e6..cefd1a05a6 100644
--- a/src/test/data/txcreatedata1.hex
+++ b/test/util/data/txcreatedata1.hex
@@ -1 +1 @@
-01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d71700000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000
+02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d71700000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000
diff --git a/test/util/data/txcreatedata1.json b/test/util/data/txcreatedata1.json
new file mode 100644
index 0000000000..e65a1859eb
--- /dev/null
+++ b/test/util/data/txcreatedata1.json
@@ -0,0 +1,44 @@
+{
+ "txid": "07894b4d12fe7853dd911402db1620920d261b9627c447f931417d330c25f06e",
+ "hash": "07894b4d12fe7853dd911402db1620920d261b9627c447f931417d330c25f06e",
+ "version": 1,
+ "size": 176,
+ "vsize": 176,
+ "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/test/util/data/txcreatedata2.hex
index 3c7644c297..d69cf58ba1 100644
--- a/src/test/data/txcreatedata2.hex
+++ b/test/util/data/txcreatedata2.hex
@@ -1 +1 @@
-01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0000000000000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000
+02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0000000000000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000
diff --git a/test/util/data/txcreatedata2.json b/test/util/data/txcreatedata2.json
new file mode 100644
index 0000000000..8f1544e1c0
--- /dev/null
+++ b/test/util/data/txcreatedata2.json
@@ -0,0 +1,44 @@
+{
+ "txid": "c14b007fa3a6c1e7765919c1d14c1cfc2b8642c3a5d3be4b1fa8c4ccfec98bb0",
+ "hash": "c14b007fa3a6c1e7765919c1d14c1cfc2b8642c3a5d3be4b1fa8c4ccfec98bb0",
+ "version": 2,
+ "size": 176,
+ "vsize": 176,
+ "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/test/util/data/txcreatedata_seq0.hex
index db02b5e4a4..54b89d2381 100644
--- a/src/test/data/txcreatedata_seq0.hex
+++ b/test/util/data/txcreatedata_seq0.hex
@@ -1 +1 @@
-01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000
+02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000
diff --git a/test/util/data/txcreatedata_seq0.json b/test/util/data/txcreatedata_seq0.json
new file mode 100644
index 0000000000..e52401f418
--- /dev/null
+++ b/test/util/data/txcreatedata_seq0.json
@@ -0,0 +1,35 @@
+{
+ "txid": "8df6ed527472542dd5e137c242a7c5a9f337ac34f7b257ae4af886aeaebb51b0",
+ "hash": "8df6ed527472542dd5e137c242a7c5a9f337ac34f7b257ae4af886aeaebb51b0",
+ "version": 2,
+ "size": 85,
+ "vsize": 85,
+ "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/test/util/data/txcreatedata_seq1.hex
index 4cedcd975c..4cedcd975c 100644
--- a/src/test/data/txcreatedata_seq1.hex
+++ b/test/util/data/txcreatedata_seq1.hex
diff --git a/test/util/data/txcreatedata_seq1.json b/test/util/data/txcreatedata_seq1.json
new file mode 100644
index 0000000000..093ff4a56b
--- /dev/null
+++ b/test/util/data/txcreatedata_seq1.json
@@ -0,0 +1,44 @@
+{
+ "txid": "c4dea671b0d7b48f8ab10bc46650e8329d3c5766931f548f513847a19f5ba75b",
+ "hash": "c4dea671b0d7b48f8ab10bc46650e8329d3c5766931f548f513847a19f5ba75b",
+ "version": 1,
+ "size": 126,
+ "vsize": 126,
+ "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/test/util/data/txcreatemultisig1.hex b/test/util/data/txcreatemultisig1.hex
new file mode 100644
index 0000000000..9c00004d38
--- /dev/null
+++ b/test/util/data/txcreatemultisig1.hex
@@ -0,0 +1 @@
+01000000000100e1f5050000000069522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae00000000
diff --git a/test/util/data/txcreatemultisig1.json b/test/util/data/txcreatemultisig1.json
new file mode 100644
index 0000000000..0cc530836a
--- /dev/null
+++ b/test/util/data/txcreatemultisig1.json
@@ -0,0 +1,28 @@
+{
+ "txid": "0d1d4edfc217d9db3ab6a9298f26a52eae3c52f55a6cb8ccbc14f7c727572894",
+ "hash": "0d1d4edfc217d9db3ab6a9298f26a52eae3c52f55a6cb8ccbc14f7c727572894",
+ "version": 1,
+ "size": 124,
+ "vsize": 124,
+ "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/test/util/data/txcreatemultisig2.hex b/test/util/data/txcreatemultisig2.hex
new file mode 100644
index 0000000000..07835c54d3
--- /dev/null
+++ b/test/util/data/txcreatemultisig2.hex
@@ -0,0 +1 @@
+01000000000100e1f5050000000017a9141c6fbaf46d64221e80cbae182c33ddf81b9294ac8700000000
diff --git a/test/util/data/txcreatemultisig2.json b/test/util/data/txcreatemultisig2.json
new file mode 100644
index 0000000000..8ad2ffdc65
--- /dev/null
+++ b/test/util/data/txcreatemultisig2.json
@@ -0,0 +1,26 @@
+{
+ "txid": "0d861f278a3b7bce7cb5a88d71e6e6a903336f95ad5a2c29b295b63835b6eee3",
+ "hash": "0d861f278a3b7bce7cb5a88d71e6e6a903336f95ad5a2c29b295b63835b6eee3",
+ "version": 1,
+ "size": 42,
+ "vsize": 42,
+ "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/test/util/data/txcreatemultisig3.hex b/test/util/data/txcreatemultisig3.hex
new file mode 100644
index 0000000000..8d34f28f87
--- /dev/null
+++ b/test/util/data/txcreatemultisig3.hex
@@ -0,0 +1 @@
+01000000000100e1f50500000000220020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f0500000000
diff --git a/test/util/data/txcreatemultisig3.json b/test/util/data/txcreatemultisig3.json
new file mode 100644
index 0000000000..086bf44b8a
--- /dev/null
+++ b/test/util/data/txcreatemultisig3.json
@@ -0,0 +1,22 @@
+{
+ "txid": "ccc552220b46a3b5140048b03395987ce4f0fa1ddf8c635bba1fa44e0f8c1d7f",
+ "hash": "ccc552220b46a3b5140048b03395987ce4f0fa1ddf8c635bba1fa44e0f8c1d7f",
+ "version": 1,
+ "size": 53,
+ "vsize": 53,
+ "locktime": 0,
+ "vin": [
+ ],
+ "vout": [
+ {
+ "value": 1.00,
+ "n": 0,
+ "scriptPubKey": {
+ "asm": "0 e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f05",
+ "hex": "0020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f05",
+ "type": "witness_v0_scripthash"
+ }
+ }
+ ],
+ "hex": "01000000000100e1f50500000000220020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f0500000000"
+}
diff --git a/test/util/data/txcreatemultisig4.hex b/test/util/data/txcreatemultisig4.hex
new file mode 100644
index 0000000000..7da54366c7
--- /dev/null
+++ b/test/util/data/txcreatemultisig4.hex
@@ -0,0 +1 @@
+01000000000100e1f5050000000017a9146edf12858999f0dae74f9c692e6694ee3621b2ac8700000000
diff --git a/test/util/data/txcreatemultisig4.json b/test/util/data/txcreatemultisig4.json
new file mode 100644
index 0000000000..d23ccc045e
--- /dev/null
+++ b/test/util/data/txcreatemultisig4.json
@@ -0,0 +1,26 @@
+{
+ "txid": "5e8b1cc73234e208d4b7ca9075f136b908c34101be7a048df4ba9ac758b61567",
+ "hash": "5e8b1cc73234e208d4b7ca9075f136b908c34101be7a048df4ba9ac758b61567",
+ "version": 1,
+ "size": 42,
+ "vsize": 42,
+ "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/test/util/data/txcreateoutpubkey1.hex b/test/util/data/txcreateoutpubkey1.hex
new file mode 100644
index 0000000000..4a08244b2f
--- /dev/null
+++ b/test/util/data/txcreateoutpubkey1.hex
@@ -0,0 +1 @@
+0100000000010000000000000000232102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397ac00000000
diff --git a/test/util/data/txcreateoutpubkey1.json b/test/util/data/txcreateoutpubkey1.json
new file mode 100644
index 0000000000..f10aaecf7a
--- /dev/null
+++ b/test/util/data/txcreateoutpubkey1.json
@@ -0,0 +1,26 @@
+{
+ "txid": "f42b38ac12e3fafc96ba1a9ba70cbfe326744aef75df5fb9db5d6e2855ca415f",
+ "hash": "f42b38ac12e3fafc96ba1a9ba70cbfe326744aef75df5fb9db5d6e2855ca415f",
+ "version": 1,
+ "size": 54,
+ "vsize": 54,
+ "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/test/util/data/txcreateoutpubkey2.hex b/test/util/data/txcreateoutpubkey2.hex
new file mode 100644
index 0000000000..8283c722ab
--- /dev/null
+++ b/test/util/data/txcreateoutpubkey2.hex
@@ -0,0 +1 @@
+0100000000010000000000000000160014a2516e770582864a6a56ed21a102044e388c62e300000000
diff --git a/test/util/data/txcreateoutpubkey2.json b/test/util/data/txcreateoutpubkey2.json
new file mode 100644
index 0000000000..5a473b76c3
--- /dev/null
+++ b/test/util/data/txcreateoutpubkey2.json
@@ -0,0 +1,22 @@
+{
+ "txid": "70f2a088cde460e677415fa1fb71895e90c231e6ed38ed203a35b6f848e9cc73",
+ "hash": "70f2a088cde460e677415fa1fb71895e90c231e6ed38ed203a35b6f848e9cc73",
+ "version": 1,
+ "size": 41,
+ "vsize": 41,
+ "locktime": 0,
+ "vin": [
+ ],
+ "vout": [
+ {
+ "value": 0.00,
+ "n": 0,
+ "scriptPubKey": {
+ "asm": "0 a2516e770582864a6a56ed21a102044e388c62e3",
+ "hex": "0014a2516e770582864a6a56ed21a102044e388c62e3",
+ "type": "witness_v0_keyhash"
+ }
+ }
+ ],
+ "hex": "0100000000010000000000000000160014a2516e770582864a6a56ed21a102044e388c62e300000000"
+}
diff --git a/test/util/data/txcreateoutpubkey3.hex b/test/util/data/txcreateoutpubkey3.hex
new file mode 100644
index 0000000000..84adff4d89
--- /dev/null
+++ b/test/util/data/txcreateoutpubkey3.hex
@@ -0,0 +1 @@
+010000000001000000000000000017a914a5ab14c9804d0d8bf02f1aea4e82780733ad0a838700000000
diff --git a/test/util/data/txcreateoutpubkey3.json b/test/util/data/txcreateoutpubkey3.json
new file mode 100644
index 0000000000..b8389b8f7e
--- /dev/null
+++ b/test/util/data/txcreateoutpubkey3.json
@@ -0,0 +1,26 @@
+{
+ "txid": "bfc7e898ee9f6a9652d7b8cca147e2da134502e2ada0f279ed634fc8cf833f8c",
+ "hash": "bfc7e898ee9f6a9652d7b8cca147e2da134502e2ada0f279ed634fc8cf833f8c",
+ "version": 1,
+ "size": 42,
+ "vsize": 42,
+ "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/test/util/data/txcreatescript1.hex b/test/util/data/txcreatescript1.hex
new file mode 100644
index 0000000000..0adce270fb
--- /dev/null
+++ b/test/util/data/txcreatescript1.hex
@@ -0,0 +1 @@
+0100000000010000000000000000017500000000
diff --git a/test/util/data/txcreatescript1.json b/test/util/data/txcreatescript1.json
new file mode 100644
index 0000000000..823168e9fb
--- /dev/null
+++ b/test/util/data/txcreatescript1.json
@@ -0,0 +1,22 @@
+{
+ "txid": "f0851b68202f736b792649cfc960259c2374badcb644ab20cac726b5f72f61c9",
+ "hash": "f0851b68202f736b792649cfc960259c2374badcb644ab20cac726b5f72f61c9",
+ "version": 1,
+ "size": 20,
+ "vsize": 20,
+ "locktime": 0,
+ "vin": [
+ ],
+ "vout": [
+ {
+ "value": 0.00,
+ "n": 0,
+ "scriptPubKey": {
+ "asm": "OP_DROP",
+ "hex": "75",
+ "type": "nonstandard"
+ }
+ }
+ ],
+ "hex": "0100000000010000000000000000017500000000"
+}
diff --git a/test/util/data/txcreatescript2.hex b/test/util/data/txcreatescript2.hex
new file mode 100644
index 0000000000..5afe8786e3
--- /dev/null
+++ b/test/util/data/txcreatescript2.hex
@@ -0,0 +1 @@
+010000000001000000000000000017a91471ed53322d470bb96657deb786b94f97dd46fb158700000000
diff --git a/test/util/data/txcreatescript2.json b/test/util/data/txcreatescript2.json
new file mode 100644
index 0000000000..d4c7e10c78
--- /dev/null
+++ b/test/util/data/txcreatescript2.json
@@ -0,0 +1,26 @@
+{
+ "txid": "6e07a7cc075e0703f32ee8c4e5373fe654bfbc315148fda364e1be286ff290d0",
+ "hash": "6e07a7cc075e0703f32ee8c4e5373fe654bfbc315148fda364e1be286ff290d0",
+ "version": 1,
+ "size": 42,
+ "vsize": 42,
+ "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/test/util/data/txcreatescript3.hex b/test/util/data/txcreatescript3.hex
new file mode 100644
index 0000000000..8a2b973bf0
--- /dev/null
+++ b/test/util/data/txcreatescript3.hex
@@ -0,0 +1 @@
+01000000000100000000000000002200200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad600000000
diff --git a/test/util/data/txcreatescript3.json b/test/util/data/txcreatescript3.json
new file mode 100644
index 0000000000..001e69511f
--- /dev/null
+++ b/test/util/data/txcreatescript3.json
@@ -0,0 +1,22 @@
+{
+ "txid": "8a234037b088e987c877030efc83374a07441c321bf9dc6dd2f206bc26507df8",
+ "hash": "8a234037b088e987c877030efc83374a07441c321bf9dc6dd2f206bc26507df8",
+ "version": 1,
+ "size": 53,
+ "vsize": 53,
+ "locktime": 0,
+ "vin": [
+ ],
+ "vout": [
+ {
+ "value": 0.00,
+ "n": 0,
+ "scriptPubKey": {
+ "asm": "0 0bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6",
+ "hex": "00200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6",
+ "type": "witness_v0_scripthash"
+ }
+ }
+ ],
+ "hex": "01000000000100000000000000002200200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad600000000"
+}
diff --git a/test/util/data/txcreatescript4.hex b/test/util/data/txcreatescript4.hex
new file mode 100644
index 0000000000..b4cfe58f42
--- /dev/null
+++ b/test/util/data/txcreatescript4.hex
@@ -0,0 +1 @@
+010000000001000000000000000017a9146a2c482f4985f57e702f325816c90e3723ca81ae8700000000
diff --git a/test/util/data/txcreatescript4.json b/test/util/data/txcreatescript4.json
new file mode 100644
index 0000000000..20094bcd44
--- /dev/null
+++ b/test/util/data/txcreatescript4.json
@@ -0,0 +1,26 @@
+{
+ "txid": "24225cf5e9391100d6b218134b9f03383ca4c880a1f634ac12990cf28b66adbc",
+ "hash": "24225cf5e9391100d6b218134b9f03383ca4c880a1f634ac12990cf28b66adbc",
+ "version": 1,
+ "size": 42,
+ "vsize": 42,
+ "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/txcreatesign.hex b/test/util/data/txcreatesignv1.hex
index a46fcc88cb..a46fcc88cb 100644
--- a/src/test/data/txcreatesign.hex
+++ b/test/util/data/txcreatesignv1.hex
diff --git a/test/util/data/txcreatesignv1.json b/test/util/data/txcreatesignv1.json
new file mode 100644
index 0000000000..519d3ab066
--- /dev/null
+++ b/test/util/data/txcreatesignv1.json
@@ -0,0 +1,35 @@
+{
+ "txid": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af",
+ "hash": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af",
+ "version": 1,
+ "size": 224,
+ "vsize": 224,
+ "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/test/util/data/txcreatesignv2.hex b/test/util/data/txcreatesignv2.hex
new file mode 100644
index 0000000000..ee425cd98c
--- /dev/null
+++ b/test/util/data/txcreatesignv2.hex
@@ -0,0 +1 @@
+02000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008a473044022079c7aa014177a2e973caf6df7c7b8f15399083b91eba370ea1e19c4caed9181e02205f8f8763505ce8e6cbdd2cd28fab3fd407a75003e7d0dc04e6bebb0a3c89e7cb01410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000